- Mybatis 介绍
- 使用jdbc编程问题总结
- Mybatis概述
- Mybatis入门程序
- {}表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换。#{}可以有效防止sql注入。 #{}可以接收简单类型值或pojo属性值。 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。
${}表示拼接sql串,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换,${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。 - 实现添加用户
- 修改用户
- 删除用户
- Mybatis解决jdbc编程的问题
- Dao开发方法
- 输入映射和输出映射
- 动态sql
- 关联查询
- Mybatis整合spring
- Mybatis逆向工程
Mybatis 介绍
ORM - Object Relational Mapping
- Hibernate - 完全的ORM - 通过对象操作
- MyBatis - 基于sql语句 - ORM
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。
使用jdbc编程问题总结
创建mysql数据库
创建数据库,将资料中的mybatis.sql脚本导入到数据库中。
创建工程
开发环境:
IDE:eclipse Mars2
JDK:1.8
1、创建一个web工程。
按下图进行创建
2、需要mysql 的数据库驱动,在资料中找到jar包。
jdbc编程步骤:
1、 加载数据库驱动
2、 创建并获取数据库链接
3、 创建jdbc statement对象
4、 设置sql语句
5、 设置sql语句中的参数(使用PreparedStatement)
6、 通过statement执行sql并获取结果
7、 对sql执行结果进行解析处理
8、 释放资源(resultSet、preparedstatement、connection)
jdbc程序
新建包com.igeek
创建测试类MybatisTest
public static void main(String[] args) {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
// 加载数据库驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 通过驱动管理类获取数据库链接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "root", "root");
// 定义sql语句 ?表示占位符
String sql = "select * from user where username = ?";
// 获取预处理statement
preparedStatement = connection.prepareStatement(sql);
// 设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值
preparedStatement.setString(1, "王五");
// 向数据库发出sql执行查询,查询出结果集
resultSet = preparedStatement.executeQuery();
// 遍历查询结果集
while (resultSet.next()) {
System.out.println(resultSet.getString("id") + " " + resultSet.getString("username"));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 释放资源
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
上边使用jdbc的原始方法(未经封装)实现了查询数据库表记录的操作。
jdbc问题总结如下:
JDBC操作数据库的流程:
A:准备数据库连接参数
B:连接数据库
C:编译SQL
D:设置SQL参数
E:执行SQL获取结果
F:遍历结果集,封装数据到JavaBean
G:关闭资源
出现的问题:
数据库连接参数硬编码到Java代码中,如果数据库环境需要改变,需要重新编译,不好!
- 解决:把数据库连接参数写到外部配置文件,通过配置文件加载参数信息、注解
SQL语句硬编码到Java代码中,业务变更、SQL优化都需要修改SQL语句,又需要重新编译,不好!
- 解决:把SQL放到外部配置文件,通过加载配置文件,解析SQL语句
SQL参数问题因为把SQL放到外部配置中,用代码加载解析,那么就引发以下新问题:
- 需要自动判断参数类型
- 需要自动判断参数位置对应关系
- 解决方案:如何自动判断参数类型和位置呢,待定?
遍历结果集非常麻烦,问题:
- 需要自己判断结果字段类型
- 需要自己明确结果字段的名称
- 需要手动封装结果字段到JavaBean中
- 如果有集合还得自己封装对象到集合中
- 解决:希望可以自动把结果集封装到JavaBean,如果有多行,可以自动封装到集合
频繁打开和创建数据库连接,比较浪费资源,效率低
- 解决:采用数据库连接池
SSH
SSM
上面的这些问题,我们自己实现起来比较繁琐,现有的持久层框架中,Hibernate也无法解决所有问题,而且Hibernate的学习成本比较高,在面对复杂查询时,查询效率略低。
Mybatis概述
简介
官网
官网:http://www.mybatis.org/mybatis-3/
中文官方文档:http://www.mybatis.org/mybatis-3/zh/index.html
特点
Mybatis:
1) 支持自定义SQL、存储过程、及高级映射
2) 实现自动对SQL的参数设置
3) 实现自动对结果集进行解析和封装
4) 通过XML或者注解进行配置和映射
实现Java对象与数据库表的映射转换
可以发现,MyBatis是对JDBC进行了简单的封装,帮助用户进行SQL参数的自动化映射,以及结果集与Java对象的映射。与Hibernate相比,更加配置简单、灵活、执行效率高。但是正因为此,所以没有实现完全自动化,需要手写SQL,这是优点也是缺点。
因此,对性能要求较高的电商类项目,一般会使用MyBatis,而对与业务逻辑复杂,不太在乎执行效率的传统行业,一般会使用Hibernate
架构
MyBatis架构总结:
- MyBatis有两类配置文件:
- mybatis-condig.xml,是MyBatis的全局配置文件,包含全局配置信息,如数据库连接参数、插件等。整个框架中只需要一个即可。
- xxxMapper.xml,是映射文件,里面配置要执行的SQL语句,每个SQL对应一个Statement,可以有多个Mapper.xml文件
- 首先会通过SqlSessionFactoryBuilder来加载配置文件,生成一个SqlSessionFactory
- 会加载mybatis-config.xml和mapper.xml
- 加载mapper.xml的时候,顺便会对Sql进行编译,形成statement
- 通过SqlSessionFactory建立连接,获取SqlSession对象
- MyBatis获取要执行的statement,进行自动参数设置
- SqlSession底层会通过Executor(执行器)来执行编译好的Statement,获取结果
- SQL的输入参数类型:
- POJO,普通Java对象
- HashMap,其实是POJO的Map形式, 键值对就是对象字段名和值
- 各种基本数据类型
- 查询结果的输出形式
- POJO,普通Java对象
- HashMap,其实是POJO的Map形式, 键值对就是对象字段名和值
- 各种基本数据类型
Mybatis入门程序
mybatis下载
mybaits的代码由github.com管理
下载地址:https://github.com/mybatis/mybatis-3/releases
课前资料提供的mybatis如下:
mybatis-3.2.7.jar mybatis的核心包
lib文件夹 mybatis的依赖包所在
mybatis-3.2.7.pdf mybatis使用手册
基于maven的引入
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
业务需求
使用MyBatis实现以下功能:
根据用户id查询一个用户
根据用户名称模糊查询用户列表
添加用户
更新用户
删除用户
环境搭建
创建web项目
mybatis_d01_c05
创建包com.igeek
创建类MybatisTest
如下图
加入jar包
加入mybatis核心包、依赖包、数据驱动包。
mybatis核心包
mybatis依赖包
数据库驱动包
效果:
加入配置文件
如下图创建资源文件夹config,加入log4j.properties和SqlMapConfig.xml配置文件
log4j配置文件
在resource目录下面创建log4j2.xml 如下:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</Console>
</Appenders>
<Loggers>
<Root level="error" >
<AppenderRef ref="Console" />
</Root>
<logger name="test" level="debug" additivity="false">
<AppenderRef ref="Console" />
</logger>
<logger name="com.igeek.servlet_bili.service" level="debug" additivity="false">
<AppenderRef ref="Console" />
</logger>
</Loggers>
</Configuration>
或者 创建log4j.properties如下:
# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
mybatis默认使用log4j作为输出日志信息。
SqlMapConfig.xml
在config下创建SqlMapConfig.xml,如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 和spring整合后 environments配置将废除 -->
<environments default="development">
<environment id="development">
<!-- 使用jdbc事务管理 -->
<transactionManager type="JDBC" />
<!-- 数据库连接池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url"
value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8" />
<property name="username" value="root" />
<property name="password" value="root" />
</dataSource>
</environment>
</environments>
</configuration>
SqlMapConfig.xml是mybatis核心配置文件,配置文件内容为数据源、事务管理。
效果
创建pojo
pojo类作为mybatis进行sql映射使用,po类通常与数据库表对应,
数据库user表如下图:
User.java如下:
public class User {
private int id;
private String username;// 用户姓名
private String sex;// 性别
private Date birthday;// 生日
private String address;// 地址
//get/set……
}
sql映射文件
在config下的sqlmap目录下创建sql映射文件User.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace:命名空间,用于隔离sql,还有一个很重要的作用,后面会讲 -->
<mapper namespace="test">
</mapper>
加载映射文件
mybatis框架需要加载Mapper.xml映射文件
将users.xml添加在SqlMapConfig.xml,如下:
<mappers>
<mapper resource="sqlmap/User.xml"/>
</mappers>
实现根据id查询用户
使用的sql:
SELECT * FROM user
WHERE id = 1
映射文件:
在user.xml中添加select标签,编写sql:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace:命名空间,用于隔离sql,还有一个很重要的作用,后面会讲 -->
<mapper namespace="test">
<!-- id:statement的id 或者叫做sql的id-->
<!-- parameterType:声明输入参数的类型 -->
<!-- resultType:声明输出结果的类型,应该填写pojo的全路径 -->
<!-- #{}:输入参数的占位符,相当于jdbc的? -->
<select id="queryUserById" parameterType="int" resultType="com.igeek.pojo.User">
SELECT * FROM `user` WHERE id = #{id}
</select>
</mapper>
测试程序:
测试程序步骤:
- 创建SqlSessionFactoryBuilder对象
- 加载SqlMapConfig.xml配置文件
- 创建SqlSessionFactory对象
- 创建SqlSession对象
- 执行SqlSession对象执行查询,获取结果User
- 打印结果
- 释放资源
MybatisTest编写测试程序如下:
public class MybatisTest {
private SqlSessionFactory sqlSessionFactory = null;
@Before
public void init() throws Exception {
// 1. 创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 2. 加载SqlMapConfig.xml配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 3. 创建SqlSessionFactory对象
this.sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
}
@Test
public void testQueryUserById() throws Exception {
// 4. 创建SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 5. 执行SqlSession对象执行查询,获取结果User
// 第一个参数是User.xml的statement的id,第二个参数是执行sql需要的参数;
Object user = sqlSession.selectOne("queryUserById", 1);
// 6. 打印结果
System.out.println(user);
// 7. 释放资源
sqlSession.close();
}
}
效果
实现根据用户名模糊查询用户
查询sql:
SELECT * FROM user
WHERE username LIKE ‘%王%’
方法一
映射文件
在User.xml配置文件中添加如下内容:
<!-- 如果返回多个结果,mybatis会自动把返回的结果放在list容器中 -->
<!-- resultType的配置和返回一个结果的配置一样 -->
<select id="queryUserByUsername1" parameterType="string" resultType="com.igeek.pojo.User">
SELECT * FROM `user` WHERE username LIKE #{username}
</select>
测试程序
MybatisTest中添加测试方法如下:
@Test
public void testQueryUserByUsername1() throws Exception {
// 4. 创建SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 5. 执行SqlSession对象执行查询,获取结果User
// 查询多条数据使用selectList方法
List<Object> list = sqlSession.selectList("queryUserByUsername1", "%王%");
// 6. 打印结果
for (Object user : list) {
System.out.println(user);
}
// 7. 释放资源
sqlSession.close();
}
效果
方法二
映射文件:
在User.xml配置文件中添加如下内容:
<!-- 如果传入的参数是简单数据类型,${}里面必须写value -->
<select id="queryUserByUsername2" parameterType="string" resultType="com.igeek.pojo.User">
SELECT * FROM `user` WHERE username LIKE '%${value}%'
</select>
测试程序:
MybatisTest中添加测试方法如下:
@Test
public void testQueryUserByUsername2() throws Exception {
// 4. 创建SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 5. 执行SqlSession对象执行查询,获取结果User
// 查询多条数据使用selectList方法
List<Object> list = sqlSession.selectList("queryUserByUsername2", "王");
// 6. 打印结果
for (Object user : list) {
System.out.println(user);
}
// 7. 释放资源
sqlSession.close();
}
效果
小结
#{}和${}
{}表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换。#{}可以有效防止sql注入。 #{}可以接收简单类型值或pojo属性值。 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。
${}表示拼接sql串,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换,${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。
parameterType和resultType
parameterType:指定输入参数类型,mybatis通过ognl从输入对象中获取参数值拼接在sql中。
resultType:指定输出结果类型,mybatis将sql查询结果的一行记录数据映射为resultType指定类型的对象。如果有多条数据,则分别进行映射,并把对象放到容器List中
selectOne和selectList
selectOne查询一条记录,如果使用selectOne查询多条记录则抛出异常:
org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 3
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:70)
selectList可以查询一条或多条记录。
实现添加用户
使用的sql:
INSERT INTO user
(username,birthday,sex,address) VALUES (‘黄忠’,’2016-07-26’,’1’,’三国’)
映射文件:
在User.xml配置文件中添加如下内容:
<!-- 保存用户 -->
<insert id="saveUser" parameterType="com.igeek.pojo.User">
INSERT INTO `user`
(username,birthday,sex,address) VALUES (#{username},#{birthday},#{sex},#{address})
</insert>
测试程序
MybatisTest中添加测试方法如下:
@Test
public void testSaveUser() {
// 4. 创建SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 5. 执行SqlSession对象执行保存
// 创建需要保存的User
User user = new User();
user.setUsername("张飞");
user.setSex("1");
user.setBirthday(new Date());
user.setAddress("蜀国");
sqlSession.insert("saveUser", user);
System.out.println(user);
// 需要进行事务提交
sqlSession.commit();
// 7. 释放资源
sqlSession.close();
}
效果
如上所示,保存成功,但是id=0,需要解决id返回不正常的问题。
mysql自增主键返回
查询id的sql
SELECT LAST_INSERT_ID()
推荐使用 useGeneratedKeys
通过修改User.xml映射文件,可以将mysql自增主键返回:
如下添加selectKey 标签
<!-- 保存用户 -->
<insert id="saveUser" parameterType="com.igeek.pojo.User">
<!-- selectKey 标签实现主键返回 -->
<!-- keyColumn:主键对应的表中的哪一列 -->
<!-- keyProperty:主键对应的pojo中的哪一个属性 -->
<!-- order:设置在执行insert语句前执行查询id的sql,还是在执行insert语句之后执行查询id的sql -->
<!-- resultType:设置返回的id的类型 -->
<selectKey keyColumn="id" keyProperty="id" order="AFTER" resultType="int">
SELECT LAST_INSERT_ID()
</selectKey>
INSERT INTO `user`
(username,birthday,sex,address) VALUES
(#{username},#{birthday},#{sex},#{address})
</insert>
LAST_INSERT_ID():是mysql的函数,返回auto_increment自增列新记录id值。
Mysql使用 uuid实现主键
需要增加通过select uuid()得到uuid值
创建表
CREATE TABLE `user1` (
`id` int(60) NULL DEFAULT NULL ,
`username` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户名称' ,
`birthday` date NULL DEFAULT NULL COMMENT '生日' ,
`sex` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '性别' ,
`address` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '地址' ,
`uuid` varchar(60) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,
PRIMARY KEY (`uuid`)
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci
ROW_FORMAT=COMPACT
;
public class User {
private int id;
private String uuid;
private String username;// 用户姓名
private String sex;// 性别
private Date birthday;// 生日
private String address;// 地址
}
<!-- 保存用户 -->
<insert id="saveUser" parameterType="com.igeek.pojo.User">
<!-- selectKey 标签实现主键返回 -->
<!-- keyColumn:主键对应的表中的哪一列 -->
<!-- keyProperty:主键对应的pojo中的哪一个属性 -->
<!-- order:设置在执行insert语句前执行查询id的sql,在执行insert语句之后执行查询id的sql -->
<!-- resultType:设置返回的id的类型 -->
<selectKey keyColumn="uuid" keyProperty="uuid" order="BEFORE" resultType="string">
SELECT uuid()
</selectKey>
INSERT INTO `user1`
(username,birthday,sex,address,uuid) VALUES
(#{username},#{birthday},#{sex},#{address},#{uuid})
</insert>
修改用户
根据用户id修改用户名
使用的sql:
UPDATE user
SET username = ‘赵云’ WHERE id = 26
映射文件
在User.xml配置文件中添加如下内容:
<!-- 更新用户 -->
<update id="updateUserById" parameterType="com.igeek.pojo.User">
UPDATE `user` SET username = #{username} WHERE id = #{id}
</update>
测试程序
MybatisTest中添加测试方法如下:
@Test
public void testUpdateUserById() {
// 4. 创建SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 5. 执行SqlSession对象执行更新
// 创建需要更新的User
User user = new User();
user.setId(26);
user.setUsername("关羽");
user.setSex("1");
user.setBirthday(new Date());
user.setAddress("蜀国");
sqlSession.update("updateUserById", user);
// 需要进行事务提交
sqlSession.commit();
// 7. 释放资源
sqlSession.close();
}
效果
删除用户
根据用户id删除用户
使用的sql
DELETE FROM user
WHERE id = 47
映射文件:
在User.xml配置文件中添加如下内容:
<!-- 删除用户 -->
<delete id="deleteUserById" parameterType="int">
delete from user where id=#{id}
</delete>
测试程序:
MybatisTest中添加测试方法如下:
@Test
public void testDeleteUserById() {
// 4. 创建SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 5. 执行SqlSession对象执行删除
sqlSession.delete("deleteUserById", 48);
// 需要进行事务提交
sqlSession.commit();
// 7. 释放资源
sqlSession.close();
}
效果
Mybatis解决jdbc编程的问题
1、 数据库连接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库连接池可解决此问题。
解决:在SqlMapConfig.xml中配置数据连接池,使用连接池管理数据库链接。
2、 Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。
解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离。
3、 向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应。
解决:Mybatis自动将java对象映射至sql语句,通过statement中的parameterType定义输入参数的类型。
4、 对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。
解决:Mybatis自动将sql执行结果映射至java对象,通过statement中的resultType定义输出结果的类型。
Dao开发方法
使用MyBatis开发Dao,通常有两个方法,即原始Dao开发方法和Mapper动态代理开发方法。
需求
使用MyBatis开发DAO实现以下的功能:
根据用户id查询一个用户信息
根据用户名称模糊查询用户信息列表
添加用户信息
SqlSession的使用范围
SqlSession中封装了对数据库的操作,如:查询、插入、更新、删除等。
SqlSession通过SqlSessionFactory创建。
SqlSessionFactory是通过SqlSessionFactoryBuilder进行创建。
SqlSessionFactoryBuilder
SqlSessionFactoryBuilder用于创建SqlSessionFacoty,SqlSessionFacoty一旦创建完成就不需要SqlSessionFactoryBuilder了,因为SqlSession是通过SqlSessionFactory创建的。所以可以将SqlSessionFactoryBuilder当成一个工具类使用,最佳使用范围是方法范围即方法体内局部变量。
SqlSessionFactory
SqlSessionFactory是一个接口,接口中定义了openSession的不同重载方法,SqlSessionFactory的最佳使用范围是整个应用运行期间,一旦创建后可以重复使用,通常以单例模式管理SqlSessionFactory。
SqlSession
SqlSession是一个面向用户的接口,sqlSession中定义了数据库操作方法。
每个线程都应该有它自己的SqlSession实例。SqlSession的实例不能共享使用,它也是线程不安全的。因此最佳的范围是请求或方法范围。绝对不能将SqlSession实例的引用放在一个类的静态字段或实例字段中。
打开一个SqlSession;使用完毕就要关闭它。通常把这个关闭操作放到 finally 块中以确保每次都能执行关闭。如下:
SqlSession session = sqlSessionFactory.openSession();
try {
// do work
} finally {
session.close();
}
原始Dao开发方式
映射文件
编写映射文件如下:(也可以使用入门程序完成的映射文件)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace:命名空间,用于隔离sql,还有一个很重要的作用,后面会讲 -->
<mapper namespace="test">
<!-- 根据id查询用户 -->
<select id="queryUserById" parameterType="int"
resultType="com.igeek.pojo.User">
select * from user where id = #{id}
</select>
<!-- 根据username模糊查询用户 -->
<select id="queryUserByUsername" parameterType="string"
resultType="com.igeek.pojo.User">
select * from user where username like '%${value}%'
</select>
<!-- 保存用户 -->
<insert id="saveUser" parameterType="com.igeek.pojo.User">
<selectKey keyProperty="id" keyColumn="id" order="AFTER"
resultType="int">
SELECT LAST_INSERT_ID()
</selectKey>
insert into user(username,birthday,sex,address)
values(#{username},#{birthday},#{sex},#{address})
</insert>
</mapper>
Dao接口
先进行DAO的接口开发,编码如下:
public interface UserDao {
/**
* 根据id查询用户
*
* @param id
* @return
*/
User queryUserById(int id);
/**
* 根据用户名模糊查询用户
*
* @param username
* @return
*/
List<User> queryUserByUsername(String username);
/**
* 保存用户
*
* @param user
*/
void saveUser(User user);
}
Dao实现类
编写的Dao实现类如下
public class UserDaoImpl implements UserDao {
private SqlSessionFactory sqlSessionFactory;
public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
super();
this.sqlSessionFactory = sqlSessionFactory;
}
@Override
public User queryUserById(int id) {
// 创建SqlSession
SqlSession sqlSession = this.sqlSessionFactory.openSession();
// 执行查询逻辑
User user = sqlSession.selectOne("queryUserById", id);
// 释放资源
sqlSession.close();
return user;
}
@Override
public List<User> queryUserByUsername(String username) {
// 创建SqlSession
SqlSession sqlSession = this.sqlSessionFactory.openSession();
// 执行查询逻辑
List<User> list = sqlSession.selectList("queryUserByUsername", username);
// 释放资源
sqlSession.close();
return list;
}
@Override
public void saveUser(User user) {
// 创建SqlSession
SqlSession sqlSession = this.sqlSessionFactory.openSession();
// 执行保存逻辑
sqlSession.insert("saveUser", user);
// 提交事务
sqlSession.commit();
// 释放资源
sqlSession.close();
}
}
Dao测试
创建一个JUnit的测试类,对UserDao进行测试,测试代码如下:
public class UserDaoTest {
private SqlSessionFactory sqlSessionFactory;
@Before
public void init() throws Exception {
// 创建SqlSessionFactoryBuilder
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 加载SqlMapConfig.xml配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 创建SqlsessionFactory
this.sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
}
@Test
public void testQueryUserById() {
// 创建DAO
UserDao userDao = new UserDaoImpl(this.sqlSessionFactory);
// 执行查询
User user = userDao.queryUserById(1);
System.out.println(user);
}
@Test
public void testQueryUserByUsername() {
// 创建DAO
UserDao userDao = new UserDaoImpl(this.sqlSessionFactory);
// 执行查询
List<User> list = userDao.queryUserByUsername("张");
for (User user : list) {
System.out.println(user);
}
}
@Test
public void testSaveUser() {
// 创建DAO
UserDao userDao = new UserDaoImpl(this.sqlSessionFactory);
// 创建保存对象
User user = new User();
user.setUsername("刘备");
user.setBirthday(new Date());
user.setSex("1");
user.setAddress("蜀国");
// 执行保存
userDao.saveUser(user);
System.out.println(user);
}
}
问题
原始Dao开发中存在以下问题:
- Dao方法体存在重复代码:通过SqlSessionFactory创建SqlSession,调用SqlSession的数据库操作方法
- 调用sqlSession的数据库操作方法需要指定statement的id,这里存在硬编码,不得于开发维护。
Mapper动态代理方式
开发规范
Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。
Mapper接口开发需要遵循以下规范:
- Mapper.xml文件中的namespace与mapper接口的类路径相同。
- Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
- Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同
Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
Mapper.xml(映射文件)
定义mapper映射文件UserMapper.xml
将UserMapper.xml放在config下mapper目录下,效果如下:
UserMapper.xml配置文件内容: ```xml <?xml version=”1.0” encoding=”UTF-8” ?> <!DOCTYPE mapper PUBLIC “-//mybatis.org//DTD Mapper 3.0//EN” “http://mybatis.org/dtd/mybatis-3-mapper.dtd">select last_insert_id() insert into user(username,birthday,sex,address) values (#{username},#{birthday},#{sex},#{address});
<a name="u2k4T"></a>
#### UserMapper(接口文件)
创建UserMapper接口代码如下:
```java
public interface UserMapper {
/**
* 根据id查询
*
* @param id
* @return
*/
User queryUserById(int id);
/**
* 根据用户名查询用户
*
* @param username
* @return
*/
List<User> queryUserByUsername(String username);
/**
* 保存用户
*
* @param user
*/
void saveUser(User user);
}
加载UserMapper.xml文件
修改SqlMapConfig.xml文件,添加以下所示的内容:
<!-- 加载映射文件 -->
<mappers>
<mapper resource="sqlmap/User.xml" />
<mapper resource="mapper/UserMapper.xml" />
</mappers>
测试
编写的测试方法如下:
public class UserMapperTest {
private SqlSessionFactory sqlSessionFactory;
@Before
public void init() throws Exception {
// 创建SqlSessionFactoryBuilder
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 加载SqlMapConfig.xml配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 创建SqlsessionFactory
this.sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
}
@Test
public void testQueryUserById() {
// 获取sqlSession,和spring整合后由spring管理
SqlSession sqlSession = this.sqlSessionFactory.openSession();
// 从sqlSession中获取Mapper接口的代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 执行查询方法
User user = userMapper.queryUserById(1);
System.out.println(user);
// 和spring整合后由spring管理
sqlSession.close();
}
@Test
public void testQueryUserByUsername() {
// 获取sqlSession,和spring整合后由spring管理
SqlSession sqlSession = this.sqlSessionFactory.openSession();
// 从sqlSession中获取Mapper接口的代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 执行查询方法
List<User> list = userMapper.queryUserByUsername("张");
for (User user : list) {
System.out.println(user);
}
// 和spring整合后由spring管理
sqlSession.close();
}
@Test
public void testSaveUser() {
// 获取sqlSession,和spring整合后由spring管理
SqlSession sqlSession = this.sqlSessionFactory.openSession();
// 从sqlSession中获取Mapper接口的代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 创建保存对象
User user = new User();
user.setUsername("刘备");
user.setBirthday(new Date());
user.setSex("1");
user.setAddress("蜀国");
// 执行查询方法
userMapper.saveUser(user);
System.out.println(user);
// 和spring整合后由spring管理
sqlSession.commit();
sqlSession.close();
}
}
小结
- selectOne和selectList
动态代理对象调用sqlSession.selectOne()和sqlSession.selectList()是根据mapper接口方法的返回值决定,如果返回list则调用selectList方法,如果返回单个对象则调用selectOne方法。
- namespace
mybatis官方推荐使用mapper代理方法开发mapper接口,程序员不用编写mapper接口实现类,使用mapper代理方法时,输入参数可以使用pojo包装对象或map对象,保证dao的通用性。
SqlMapConfig.xml配置文件
配置内容
SqlMapConfig.xml中配置的内容和顺序如下:
properties(属性)
settings(全局配置参数)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境集合属性对象)
environment(环境子属性对象)
transactionManager(事务管理)
dataSource(数据源)
mappers(映射器)
properties(属性)
SqlMapConfig.xml可以引用java属性文件中的配置信息如下:
在config下定义db.properties文件,如下所示:
db.properties配置文件内容如下:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8
jdbc.username=root
jdbc.password=root
SqlMapConfig.xml引用如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 是用resource属性加载外部配置文件 -->
<properties resource="db.properties">
<!-- 在properties内部用property定义属性 -->
<!-- 如果外部配置文件有该属性,则内部定义属性被外部属性覆盖 -->
<property name="jdbc.username" value="root123" />
<property name="jdbc.password" value="root123" />
</properties>
<!-- 和spring整合后 environments配置将废除 -->
<environments default="development">
<environment id="development">
<!-- 使用jdbc事务管理 -->
<transactionManager type="JDBC" />
<!-- 数据库连接池 -->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
<!-- 加载映射文件 -->
<mappers>
<mapper resource="sqlmap/User.xml" />
<mapper resource="mapper/UserMapper.xml" />
</mappers>
</configuration>
注意:MyBatis 将按照下面的顺序来加载属性:
- 在properties 元素体内定义的属性首先被读取。
- 然后会读取properties 元素中resource或 url 加载的属性,它会覆盖已读取的同名属性。
typeAliases(类型别名)
mybatis支持别名:
别名 | 映射的类型 |
---|---|
_byte | byte |
_long | long |
_short | short |
_int | int |
_integer | int |
_double | double |
_float | float |
_boolean | boolean |
string | String |
byte | Byte |
long | Long |
short | Short |
int | Integer |
integer | Integer |
double | Double |
float | Float |
boolean | Boolean |
date | Date |
decimal | BigDecimal |
bigdecimal | BigDecimal |
map | Map |
自定义别名:
在SqlMapConfig.xml中配置如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 是用resource属性加载外部配置文件 -->
<properties resource="db.properties">
<!-- 在properties内部用property定义属性 -->
<property name="jdbc.username" value="root123" />
<property name="jdbc.password" value="root123" />
</properties>
<typeAliases>
<!-- 单个别名定义 -->
<typeAlias alias="user" type="com.igeek.pojo.User" />
<!-- 批量别名定义,扫描整个包下的类,别名为类名(大小写不敏感) -->
<package name="com.igeek.pojo" />
<package name="其它包" />
</typeAliases>
<!-- 和spring整合后 environments配置将废除 -->
<environments default="development">
<environment id="development">
<!-- 使用jdbc事务管理 -->
<transactionManager type="JDBC" />
<!-- 数据库连接池 -->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
<!-- 加载映射文件 -->
<mappers>
<mapper resource="sqlmap/User.xml" />
<mapper resource="mapper/UserMapper.xml" />
</mappers>
</configuration>
在mapper.xml配置文件中,就可以使用设置的别名了
别名大小写不敏感
mappers(映射器)
使用相对于类路径的资源(现在的使用方式)
如:
使用mapper接口类路径
如:
注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。
注册指定包下的所有mapper接口
如:
注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。
输入映射和输出映射
Mapper.xml映射文件中定义了操作数据库的sql,每个sql是一个statement,映射文件是mybatis的核心。
环境准备
- 复制昨天的工程,如下图
- 只保留Mapper接口开发相关的文件,其他的删除
最终效果如下图:
如下图修改SqlMapConfig.xml配置文件。Mapper映射器只保留包扫描的方式
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 是用resource属性加载外部配置文件 --> <properties resource="db.properties"></properties> <typeAliases> <package name="com.igeek" /> </typeAliases> <!-- 和spring整合后 environments配置将废除 --> <environments default="development"> <environment id="development"> <!-- 使用jdbc事务管理 --> <transactionManager type="JDBC" /> <!-- 数据库连接池 --> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </dataSource> </environment> </environments> <!-- 加载映射文件 --> <mappers> <!-- 使用包扫描的方式 --> <package name="com.igeek"/> </mappers> </configuration>
parameterType(输入类型)
传递简单类型
参考第一天内容。
使用#{}占位符,或者${}进行sql拼接。传递pojo对象
参考第一天的内容。
Mybatis使用ognl表达式解析对象字段的值,#{}或者${}括号中的值为pojo属性名称。传递pojo包装对象
开发中可以使用pojo传递查询条件。
查询条件可能是综合的查询条件,不仅包括用户查询条件还包括其它的查询条件(比如查询用户信息的时候,将用户购买商品信息也作为查询条件),这时可以使用包装对象传递输入参数。
包装对象:Pojo类中的一个属性是另外一个pojo。
需求:根据用户名模糊查询用户信息,查询条件放到QueryVo的user属性中。
编写QueryVo
public class QueryVo {
// 包含其他的pojo
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
Sql语句
SELECT * FROM user WHERE username LIKE ‘%张%’
Mapper.xml文件
在UserMapper.xml中配置sql,如下图。
<!-- 使用包装类型查询用户 -->
<select id="queryUserByQueryVo" parameterType="queryVo" resultType="user">
SELECT * FROM `user` WHERE username LIKE '%${user.username}%'
</select>
Mapper接口
在UserMapper接口中添加方法,如下图:
/**
*
* @Title: queryUserByQueryVo
* @Description: TODO(根据包装类查询用户)
* @param queryVo
* @return
*/
List<User> queryUserByQueryVo(QueryVo queryVo);
测试方法
在UserMapeprTest增加测试方法,如下:
@Test
public void testQueryUserByQueryVo() {
// mybatis和spring整合,整合之后,交给spring管理
SqlSession sqlSession = this.sqlSessionFactory.openSession();
// 创建Mapper接口的动态代理对象,整合之后,交给spring管理
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 使用userMapper执行查询,使用包装对象
QueryVo queryVo = new QueryVo();
// 设置user条件
User user = new User();
user.setUsername("张");
// 设置到包装对象中
queryVo.setUser(user);
// 执行查询
List<User> list = userMapper.queryUserByQueryVo(queryVo);
for (User u : list) {
System.out.println(u);
}
// mybatis和spring整合,整合之后,交给spring管理
sqlSession.close();
}
效果
resultType(输出类型)
输出简单类型
需求:查询用户表数据条数
sql:SELECT count(*) FROM user
Mapper.xml文件
在UserMapper.xml中配置sql:
<!-- 查询用户表数据条数 -->
<select id="queryUserCount" resultType="int">
SELECT count(*) FROM `user`
</select>
Mapper接口
在UserMapper添加方法,:
/**
*
* @Title: queryUserCount
* @Description: TODO(这里用一句话描述这个方法的作用)
* @return
*/
int queryUserCount();
测试方法
在UserMapeprTest增加测试方法,如下:
@Test
public void testQueryUserCount() {
// mybatis和spring整合,整合之后,交给spring管理
SqlSession sqlSession = this.sqlSessionFactory.openSession();
// 创建Mapper接口的动态代理对象,整合之后,交给spring管理
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 使用userMapper执行查询用户数据条数
int count = userMapper.queryUserCount();
System.out.println(count);
// mybatis和spring整合,整合之后,交给spring管理
sqlSession.close();
}
效果
测试结果如下图:
注意:输出简单类型必须查询出来的结果集有一条记录,最终将第一个字段的值转换为输出类型。
输出pojo对象
输出pojo列表
resultMap
resultType可以指定将查询结果映射为pojo,但需要pojo的属性名和sql查询的列名一致方可映射成功。
如果sql查询字段名和pojo的属性名不一致,可以通过resultMap将字段名和属性名作一个对应关系 ,resultMap实质上还需要将查询结果映射到pojo对象中。
resultMap可以实现将查询结果映射为复杂类型的pojo,比如在查询结果映射对象中包括pojo和list实现一对一查询和一对多查询。
需求:查询订单表order的所有数据
sql:SELECT id, user_id, number, createtime, note FROM order
声明pojo对象
数据库表如下图:
Order对象:
public class Order {
// 订单id
private int id;
// 用户id
private Integer userId;
// 订单号
private String number;
// 订单创建时间
private Date createtime;
// 备注
private String note;
//get/set。。。
}
Mapper.xml文件
创建OrderMapper.xml配置文件,如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace:命名空间,用于隔离sql,还有一个很重要的作用,Mapper动态代理开发的时候使用,需要指定Mapper的类路径 -->
<mapper namespace="com.igeek.mapper.OrderMapper">
<!-- 查询所有的订单数据 -->
<select id="queryOrderAll" resultType="order">
SELECT id, user_id,
number,
createtime, note FROM `orders`
</select>
</mapper>
Mapper接口
编写接口如下:
public interface OrderMapper {
/**
* 查询所有订单
*
* @return
*/
List<Order> queryOrderAll();
}
测试方法
编写测试方法OrderMapperTest如下:
public class OrderMapperTest {
private SqlSessionFactory sqlSessionFactory;
@Before
public void init() throws Exception {
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
this.sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void testQueryAll() {
// 获取sqlSession
SqlSession sqlSession = this.sqlSessionFactory.openSession();
// 获取OrderMapper
OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
// 执行查询
List<Order> list = orderMapper.queryOrderAll();
for (Order order : list) {
System.out.println(order);
}
}
}
效果
测试效果如下图:
发现userId为null
解决方案:使用resultMap
使用resultMap
由于上边的mapper.xml中sql查询列(user_id)和Order类属性(userId)不一致,所以查询结果不能映射到pojo中。
需要定义resultMap,把orderResultMap将sql查询列(user_id)和Order类属性(userId)对应起来
改造OrderMapper.xml,如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace:命名空间,用于隔离sql,还有一个很重要的作用,Mapper动态代理开发的时候使用,需要指定Mapper的类路径 -->
<mapper namespace="com.igeek.mapper.OrderMapper">
<!-- resultMap最终还是要将结果映射到pojo上,type就是指定映射到哪一个pojo -->
<!-- id:设置ResultMap的id -->
<resultMap type="order" id="orderResultMap">
<!-- 定义主键 ,非常重要。如果是多个字段,则定义多个id -->
<!-- property:主键在pojo中的属性名 -->
<!-- column:主键在数据库中的列名 -->
<id property="id" column="id" />
<!-- 定义普通属性 -->
<result property="userId" column="user_id" />
<result property="number" column="number" />
<result property="createtime" column="createtime" />
<result property="note" column="note" />
</resultMap>
<!-- 查询所有的订单数据 -->
<select id="queryOrderAll" resultMap="orderResultMap">
SELECT id, user_id,
number,
createtime, note FROM `orders`
</select>
</mapper>
效果
动态sql
通过mybatis提供的各种标签方法实现动态拼接sql。
需求:根据性别和名字查询用户
查询sql:
SELECT id, username, birthday, sex, address FROM user
WHERE sex = 1 AND username LIKE ‘%张%’
If标签
Mapper.xml文件
UserMapper.xml配置sql,如下:
<!-- 根据条件查询用户 -->
<select id="queryUserByWhere" parameterType="user" resultType="user">
SELECT id, username, birthday, sex, address FROM `user`
WHERE sex = #{sex} AND username LIKE
'%${username}%'
</select>
Mapper接口
编写Mapper接口:
/**
*
* @Title: queryUserByWhere
* @Description: 根据条件查询用户
* @param user
* @return
*/
List<User> queryUserByWhere(User user);
测试方法
在UserMapperTest添加测试方法,如下:
@Test
public void testQueryUserByWhere() {
// mybatis和spring整合,整合之后,交给spring管理
SqlSession sqlSession = this.sqlSessionFactory.openSession();
// 创建Mapper接口的动态代理对象,整合之后,交给spring管理
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 使用userMapper执行根据条件查询用户
User user = new User();
user.setSex("1");
user.setUsername("张");
List<User> list = userMapper.queryUserByWhere(user);
for (User u : list) {
System.out.println(u);
}
// mybatis和spring整合,整合之后,交给spring管理
sqlSession.close();
}
效果
测试效果如下图:
如果注释掉 user.setSex(“1”),测试结果如下图:
测试结果二很显然不合理。
按照之前所学的,要解决这个问题,需要编写多个sql,查询条件越多,需要编写的sql就更多了,显然这样是不靠谱的。
使用if标签
改造UserMapper.xml,如下:
<!-- 根据条件查询用户 -->
<select id="queryUserByWhere" parameterType="user" resultType="user">
SELECT id, username, birthday, sex, address FROM `user`
WHERE 1=1
<if test="sex != null and sex != ''">
AND sex = #{sex}
</if>
<if test="username != null and username != ''">
AND username LIKE
'%${username}%'
</if>
</select>
效果
Where标签
上面的sql还有where 1=1 这样的语句,很麻烦
可以使用where标签进行改造
改造UserMapper.xml,如下
<!-- 根据条件查询用户 -->
<select id="queryUserByWhere" parameterType="user" resultType="user">
SELECT id, username, birthday, sex, address FROM `user`
<!-- where标签可以自动添加where,同时处理sql语句中第一个and关键字 -->
<where>
<if test="sex != null">
AND sex = #{sex}
</if>
<if test="username != null and username != ''">
AND username LIKE
'%${username}%'
</if>
</where>
</select>
效果
Sql片段
Sql中可将重复的sql提取出来,使用时用include引用即可,最终达到sql重用的目的。
把上面例子中的id, username, birthday, sex, address提取出来,作为sql片段,如下:
<!-- 声明sql片段 -->
<sql id="userFields">
id, username, birthday, sex, address
</sql>
<!-- 根据条件查询用户 -->
<select id="queryUserByWhere" parameterType="user" resultType="user">
<!-- SELECT id, username, birthday, sex, address FROM `user` -->
<!-- 使用include标签加载sql片段;refid是sql片段id -->
SELECT <include refid="userFields" /> FROM `user`
<!-- where标签可以自动添加where关键字,同时处理sql语句中第一个and关键字 -->
<where>
<if test="sex != null">
AND sex = #{sex}
</if>
<if test="username != null and username != ''">
AND username LIKE
'%${username}%'
</if>
</where>
</select>
如果要使用别的Mapper.xml配置的sql片段,可以在refid前面加上对应的Mapper.xml的namespace
例如下图
foreach标签
向sql传递数组或List,mybatis使用foreach解析,如下:
根据多个id查询用户信息
查询sql:
SELECT * FROM user WHERE id IN (1,10,24)
改造QueryVo
如下代码,在pojo中定义list属性ids存储多个用户id,并添加getter/setter方法
public class QueryVo {
// 包含其他的pojo
private User user;
private List<Integer> ids;
public List<Integer> getIds() {
return ids;
}
public void setIds(List<Integer> ids) {
this.ids = ids;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
Mapper.xml文件
UserMapper.xml添加sql,如下:
<!-- 根据ids查询用户 -->
<select id="queryUserByIds" parameterType="queryVo" resultType="user">
SELECT * FROM `user`
<where>
<!-- foreach标签,进行遍历 -->
<!-- collection:遍历的集合,这里是QueryVo的ids属性 -->
<!-- item:遍历的项目,可以随便写,,但是和后面的#{}里面要一致 -->
<!-- open:在前面添加的sql片段 -->
<!-- close:在结尾处添加的sql片段 -->
<!-- separator:指定遍历的元素之间使用的分隔符 -->
<foreach collection="ids" item="item" open="id IN (" close=")" separator=",">
#{item}
</foreach>
</where>
</select>
在UserMapper接口中添加如下方法
List<User> queryUserByIds(QueryVo queryVo);
测试方法如下图:
@Test
public void testQueryUserByIds() {
// mybatis和spring整合,整合之后,交给spring管理
SqlSession sqlSession = this.sqlSessionFactory.openSession();
// 创建Mapper接口的动态代理对象,整合之后,交给spring管理
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 使用userMapper执行根据条件查询用户
QueryVo queryVo = new QueryVo();
List<Integer> ids = new ArrayList<>();
ids.add(1);
ids.add(10);
ids.add(24);
queryVo.setIds(ids);
List<User> list = userMapper.queryUserByIds(queryVo);
for (User u : list) {
System.out.println(u);
}
// mybatis和spring整合,整合之后,交给spring管理
sqlSession.close();
}
效果
关联查询
商品订单数据模型
一对一查询
需求:查询所有订单信息,关联查询下单用户信息。
注意:因为一个订单信息只会是一个人下的订单,所以从查询订单信息出发关联查询用户信息为一对一查询。如果从用户信息出发查询用户下的订单信息则为一对多查询,因为一个用户可以下多个订单。
sql语句:
SELECT
o.id,
o.user_id userId,
o.number,
o.createtime,
o.note,
u.username,
u.address
FROM
`orders` o
LEFT JOIN `user` u ON o.user_id = u.id
方法一:使用resultType
使用resultType,改造订单pojo类,此pojo类中包括了订单信息和用户信息
这样返回对象的时候,mybatis自动把用户信息也注入进来了
改造pojo类
OrderUser类继承Order类后OrderUser类包括了Order类的所有字段,只需要定义用户的信息字段即可,如下:
public class OrderUser extends Order{
private String username;
private String address;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
Mapper.xml
在UserMapper.xml添加sql,如下
<!-- 查询订单,同时包含用户数据 -->
<select id="queryOrderUser" resultType="orderUser">
SELECT
o.id,
o.user_id
userId,
o.number,
o.createtime,
o.note,
u.username,
u.address
FROM
`orders` o
LEFT JOIN `user` u ON o.user_id = u.id
</select>
Mapper接口
在UserMapper接口添加方法,如下代码:
/**
*
* @Title: queryOrderUser
* @Description: TODO(一对一关联,查询订单同时包含用户信息)
* @return
*/
List<OrderUser> queryOrderUser();
测试方法:
在UserMapperTest添加测试方法,如下:
@Test
public void testQueryOrderUser() {
// mybatis和spring整合,整合之后,交给spring管理
SqlSession sqlSession = this.sqlSessionFactory.openSession();
// 创建Mapper接口的动态代理对象,整合之后,交给spring管理
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 使用userMapper执行根据条件查询用户
List<OrderUser> list = userMapper.queryOrderUser();
for (OrderUser ou : list) {
System.out.println(ou);
}
// mybatis和spring整合,整合之后,交给spring管理
sqlSession.close();
}
效果
小结
定义专门的pojo类作为输出类型,其中定义了sql查询结果集所有的字段。此方法较为简单,企业中使用普遍。
方法二:使用resultMap
使用resultMap,定义专门的resultMap用于映射一对一查询结果。
改造pojo类
在Order类中加入User属性,user属性中用于存储关联查询的用户信息,因为订单关联查询用户是一对一关系,所以这里使用单个User对象存储关联查询的用户信息。
改造Order如下代码:
public class Order {
// 订单id
private int id;
// 用户id
private Integer userId;
// 订单号
private String number;
// 订单创建时间
private Date createtime;
// 备注
private String note;
private User user;
//get/set。。。
}
Mapper.xml
这里resultMap指定orderUserResultMap,如下:
<resultMap type="order" id="orderUserResultMap">
<id property="id" column="id" />
<result property="userId" column="user_id" />
<result property="number" column="number" />
<result property="createtime" column="createtime" />
<result property="note" column="note" />
<!-- association :配置一对一属性 -->
<!-- property:Order里面的User属性名 -->
<!-- javaType:属性类型 -->
<association property="user" javaType="user">
<!-- id:声明主键,表示user_id是关联查询对象的唯一标识-->
<id property="id" column="user_id" />
<result property="username" column="username" />
<result property="address" column="address" />
</association>
</resultMap>
<!-- 一对一关联,查询订单,订单内部包含用户属性 -->
<select id="queryOrderUserResultMap" resultMap="orderUserResultMap">
SELECT
o.id,
o.user_id,
o.number,
o.createtime,
o.note,
u.username,
u.address
FROM
`orders` o
LEFT JOIN `user` u ON o.user_id = u.id
</select>
Mapper接口
编写UserMapper如下代码:
/**
*
* @Title: queryOrderUserResultMap
* @Description: TODO(一对一关联,查询订单,订单内部包含用户属性 )
* @return
*/
List<Order> queryOrderUserResultMap();
测试方法
在UserMapperTest增加测试方法,如下:
@Test
public void testQueryOrderUserResultMap() {
// mybatis和spring整合,整合之后,交给spring管理
SqlSession sqlSession = this.sqlSessionFactory.openSession();
// 创建Mapper接口的动态代理对象,整合之后,交给spring管理
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 使用userMapper执行根据条件查询用户
List<Order> list = userMapper.queryOrderUserResultMap();
for (Order o : list) {
System.out.println(o);
}
// mybatis和spring整合,整合之后,交给spring管理
sqlSession.close();
}
效果
一对多查询
案例:查询所有用户信息及用户关联的订单信息。
用户信息和订单信息为一对多关系。
sql语句:
SELECT
u.id,
u.username,
u.birthday,
u.sex,
u.address,
o.id oid,
o.number,
o.createtime,
o.note
FROM
`user` u
LEFT JOIN `orders` o ON u.id = o.user_id
修改pojo类
Mapper.xml
在UserMapper.xml添加sql,如下:
<resultMap type="user" id="userOrderResultMap">
<id property="id" column="id" />
<result property="username" column="username" />
<result property="birthday" column="birthday" />
<result property="sex" column="sex" />
<result property="address" column="address" />
<!-- 配置一对多的关系 -->
<collection property="orders" javaType="list" ofType="order">
<!-- 配置主键,是关联Order的唯一标识 -->
<id property="id" column="oid" />
<result property="number" column="number" />
<result property="createtime" column="createtime" />
<result property="note" column="note" />
</collection>
</resultMap>
<!-- 一对多关联,查询订单同时查询该用户下的订单 -->
<select id="queryUserOrder" resultMap="userOrderResultMap">
SELECT
u.id,
u.username,
u.birthday,
u.sex,
u.address,
o.id oid,
o.number,
o.createtime,
o.note
FROM
`user` u
LEFT JOIN `orders` o ON u.id = o.user_id
</select>
Mapper接口
测试方法
在UserMapperTest增加测试方法,如下
@Test
public void testQueryUserOrder() {
// mybatis和spring整合,整合之后,交给spring管理
SqlSession sqlSession = this.sqlSessionFactory.openSession();
// 创建Mapper接口的动态代理对象,整合之后,交给spring管理
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 使用userMapper执行根据条件查询用户
List<User> list = userMapper.queryUserOrder();
for (User u : list) {
System.out.println(u);
}
// mybatis和spring整合,整合之后,交给spring管理
sqlSession.close();
}
效果
Mybatis整合spring
整合思路
- SqlSessionFactory对象应该放到spring容器中作为单例存在。
- 传统dao的开发方式中,应该从spring容器中获得sqlsession对象。
- Mapper代理形式中,应该从spring容器中直接获得mapper的代理对象。
数据库的连接以及数据库连接池事务管理都交给spring容器来完成。
整合需要的jar包
1、spring的jar包
2、Mybatis的jar包
3、Spring+mybatis的整合包。
4、Mysql的数据库驱动jar包。
5、数据库连接池的jar包。
jar包位置如下所示:
整合的步骤
创建工程
导入jar包
加入配置文件
mybatis的配置文件 sqlmapConfig.xml
- Spring的配置文件 applicationContext.xml
- 数据库连接及连接池
- 事务管理(暂时可以不配置)
- sqlsessionFactory对象,配置到spring容器中
- mapeer代理对象或者是dao实现类配置到spring容器中
SqlMapConfig.xml
配置文件是SqlMapConfig.xml,如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 设置别名 -->
<typeAliases>
<!-- 2. 指定扫描包,会把包内所有的类都设置别名,别名的名称就是类名,大小写不敏感 -->
<package name="com.igeek.pojo" />
</typeAliases>
</configuration>
applicationContext.xml
SqlSessionFactoryBean属于mybatis-spring这个jar包
对于spring来说,mybatis是另外一个架构,需要整合jar包。
在项目中加入mybatis-spring-1.2.2.jar的源码,如下图
效果,如下图所示,图标变化,表示源码加载成功:
整合Mybatis需要的是SqlSessionFactoryBean,位置如下图:
applicationContext.xml,配置内容如下
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<!-- 加载配置文件 -->
<context:property-placeholder location="classpath:db.properties" />
<!-- 数据库连接池 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="maxActive" value="10" />
<property name="maxIdle" value="5" />
</bean>
<!-- 配置SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 配置mybatis核心配置文件 -->
<property name="configLocation" value="classpath:SqlMapConfig.xml" />
<!-- 配置数据源 -->
<property name="dataSource" ref="dataSource" />
</bean>
</beans>
db.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8
jdbc.username=root
jdbc.password=root
log4j2配置文件
使用log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</Console>
</Appenders>
<Loggers>
<Root level="error" >
<AppenderRef ref="Console" />
</Root>
<logger name="com.igeek.servlet_bili.mapper" level="debug" additivity="false">
<AppenderRef ref="Console" />
</logger>
</Loggers>
</Configuration>
或者log4j.properties
# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
效果:
Dao的开发
两种dao的实现方式:
- 原始dao的开发方式
- 使用Mapper代理形式开发方式
- 直接配置Mapper代理
- 使用扫描包配置Mapper代理
需求:
1. 实现根据用户id查询
2. 实现根据用户名模糊查询
3. 添加用户
创建pojo
public class User {
private int id;
private String username;// 用户姓名
private String sex;// 性别
private Date birthday;// 生日
private String address;// 地址
//get/set。。。
}
传统dao的开发方式
原始的DAO开发接口+实现类来完成。
需要dao实现类需要继承SqlsessionDaoSupport类
实现Mapper.xml
编写User.xml配置文件,如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="test">
<!-- 根据用户id查询 -->
<select id="queryUserById" parameterType="int" resultType="user">
select * from user where id = #{id}
</select>
<!-- 根据用户名模糊查询用户 -->
<select id="queryUserByUsername" parameterType="string"
resultType="user">
select * from user where username like '%${value}%'
</select>
<!-- 添加用户 -->
<insert id="saveUser" parameterType="user">
<selectKey keyProperty="id" keyColumn="id" order="AFTER"
resultType="int">
select last_insert_id()
</selectKey>
insert into user
(username,birthday,sex,address)
values
(#{username},#{birthday},#{sex},#{address})
</insert>
</mapper>
加载Mapper.xml
实现UserDao接口
public interface UserDao {
/**
* 根据id查询用户
*
* @param id
* @return
*/
User queryUserById(int id);
/**
* 根据用户名模糊查询用户列表
*
* @param username
* @return
*/
List<User> queryUserByUsername(String username);
/**
* 保存
*
* @param user
*/
void saveUser(User user);
}
实现UserDaoImpl实现类
编写DAO实现类,实现类必须集成SqlSessionDaoSupport
SqlSessionDaoSupport提供getSqlSession()方法来获取SqlSession
public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao {
@Override
public User queryUserById(int id) {
// 获取SqlSession
SqlSession sqlSession = super.getSqlSession();
// 使用SqlSession执行操作
User user = sqlSession.selectOne("queryUserById", id);
// 不要关闭sqlSession
return user;
}
@Override
public List<User> queryUserByUsername(String username) {
// 获取SqlSession
SqlSession sqlSession = super.getSqlSession();
// 使用SqlSession执行操作
List<User> list = sqlSession.selectList("queryUserByUsername", username);
// 不要关闭sqlSession
return list;
}
@Override
public void saveUser(User user) {
// 获取SqlSession
SqlSession sqlSession = super.getSqlSession();
// 使用SqlSession执行操作
sqlSession.insert("saveUser", user);
// 不用提交,事务由spring进行管理
// 不要关闭sqlSession
}
}
配置dao
把dao实现类配置到spring容器中,如下图
<!-- 原始方法开始dao,配置dao到spring中 -->
<bean id="userDao" class="com.igeek.dao.UserDaoImpl">
<!--配置sqlSessionFactory -->
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
测试方法
创建测试方法,可以直接创建测试Junit用例。
创建包:com.igeek.test
编写测试方法如下:
public class UserDaoTest {
private ApplicationContext context;
@Before
public void setUp() throws Exception {
this.context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
}
@Test
public void testQueryUserById() {
// 获取userDao
UserDao userDao = this.context.getBean(UserDao.class);
User user = userDao.queryUserById(1);
System.out.println(user);
}
@Test
public void testQueryUserByUsername() {
// 获取userDao
UserDao userDao = this.context.getBean(UserDao.class);
List<User> list = userDao.queryUserByUsername("张");
for (User user : list) {
System.out.println(user);
}
}
@Test
public void testSaveUser() {
// 获取userDao
UserDao userDao = this.context.getBean(UserDao.class);
User user = new User();
user.setUsername("曹操");
user.setSex("1");
user.setBirthday(new Date());
user.setAddress("三国");
userDao.saveUser(user);
System.out.println(user);
}
}
Mapper代理形式开发dao
实现Mapper.xml
编写UserMapper.xml配置文件,如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.igeek.mapper.UserMapper">
<!-- 根据用户id查询 -->
<select id="queryUserById" parameterType="int" resultType="user">
select * from user where id = #{id}
</select>
<!-- 根据用户名模糊查询用户 -->
<select id="queryUserByUsername" parameterType="string"
resultType="user">
select * from user where username like '%${value}%'
</select>
<!-- 添加用户 -->
<insert id="saveUser" parameterType="user">
<selectKey keyProperty="id" keyColumn="id" order="AFTER"
resultType="int">
select last_insert_id()
</selectKey>
insert into user
(username,birthday,sex,address) values
(#{username},#{birthday},#{sex},#{address})
</insert>
</mapper>
实现UserMapper接口
public interface UserMapper {
/**
* 根据用户id查询
*
* @param id
* @return
*/
User queryUserById(int id);
/**
* 根据用户名模糊查询用户
*
* @param username
* @return
*/
List<User> queryUserByUsername(String username);
/**
* 添加用户
*
* @param user
*/
void saveUser(User user);
}
方式一:配置mapper代理
在applicationContext.xml添加配置
MapperFactoryBean也是属于mybatis-spring整合包
<!-- Mapper代理的方式开发方式一,配置Mapper代理对象 -->
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<!-- 配置Mapper接口 -->
<property name="mapperInterface" value="com.igeek.mapper.UserMapper" />
<!-- 配置sqlSessionFactory -->
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
测试方法
public class UserMapperTest {
private ApplicationContext context;
@Before
public void setUp() throws Exception {
this.context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
}
@Test
public void testQueryUserById() {
// 获取Mapper
UserMapper userMapper = this.context.getBean(UserMapper.class);
User user = userMapper.queryUserById(1);
System.out.println(user);
}
@Test
public void testQueryUserByUsername() {
// 获取Mapper
UserMapper userMapper = this.context.getBean(UserMapper.class);
List<User> list = userMapper.queryUserByUsername("张");
for (User user : list) {
System.out.println(user);
}
}
@Test
public void testSaveUser() {
// 获取Mapper
UserMapper userMapper = this.context.getBean(UserMapper.class);
User user = new User();
user.setUsername("曹操");
user.setSex("1");
user.setBirthday(new Date());
user.setAddress("三国");
userMapper.saveUser(user);
System.out.println(user);
}
}
方式二:扫描包形式配置mapper
<!-- Mapper代理的方式开发方式二,扫描包方式配置代理 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 配置Mapper接口 -->
<property name="basePackage" value="com.igeek.mapper" />
</bean>
每个mapper代理对象的id就是类名,首字母小写
Mybatis逆向工程
使用官方网站的Mapper自动生成工具mybatis-generator-core-1.3.2来生成po类和Mapper映射文件
导入逆向工程
导入逆向工程到eclipse中
修改配置文件
在generatorConfig.xml中配置Mapper生成的详细信息,如下图:
注意修改以下几点:
1. 修改要生成的数据库表
2. pojo文件所在包路径
3. Mapper所在的包路径
配置文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="testTables" targetRuntime="MyBatis3">
<commentGenerator>
<!-- 是否去除自动生成的注释 true:是 : false:否 -->
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!--数据库连接的信息:驱动类、连接地址、用户名、密码 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mybatis" userId="root" password="root">
</jdbcConnection>
<!-- <jdbcConnection driverClass="oracle.jdbc.OracleDriver" connectionURL="jdbc:oracle:thin:@127.0.0.1:1521:yycg"
userId="yycg" password="yycg"> </jdbcConnection> -->
<!-- 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer,为 true时把JDBC DECIMAL
和 NUMERIC 类型解析为java.math.BigDecimal -->
<javaTypeResolver>
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!-- targetProject:生成PO类的位置 -->
<javaModelGenerator targetPackage="com.igeek.ssm.po"
targetProject=".\src">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false" />
<!-- 从数据库返回的值被清理前后的空格 -->
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- targetProject:mapper映射文件生成的位置 -->
<sqlMapGenerator targetPackage="com.igeek.ssm.mapper"
targetProject=".\src">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false" />
</sqlMapGenerator>
<!-- targetPackage:mapper接口生成的位置 -->
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.igeek.ssm.mapper" targetProject=".\src">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false" />
</javaClientGenerator>
<!-- 指定数据库表 -->
<table schema="" tableName="user"></table>
<table schema="" tableName="orders"></table>
</context>
</generatorConfiguration>
生成逆向工程代码
找到下图所示的java文件,执行工程main主函数,
刷新工程,发现代码生成,如下图:
测试逆向工程代码
- 复制生成的代码到mybatis_d02_c05工程,如下图
- 修改spring配置文件
在applicationContext.xml修改
<!-- Mapper代理的方式开发,扫描包方式配置代理 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 配置Mapper接口,如果需要加载多个包,直接写进来,中间用,分隔 -->
<!-- <property name="basePackage" value="com.igeek.mapper" /> -->
<property name="basePackage" value="com.igeek.ssm.mapper" />
</bean>
编写测试方法:
public class UserMapperTest { private ApplicationContext context; @Before public void setUp() throws Exception { this.context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); } @Test public void testInsert() { // 获取Mapper UserMapper userMapper = this.context.getBean(UserMapper.class); User user = new User(); user.setUsername("曹操"); user.setSex("1"); user.setBirthday(new Date()); user.setAddress("三国"); userMapper.insert(user); } @Test public void testSelectByExample() { // 获取Mapper UserMapper userMapper = this.context.getBean(UserMapper.class); // 创建User对象扩展类,用户设置查询条件 UserExample example = new UserExample(); example.createCriteria().andUsernameLike("%张%"); // 查询数据 List<User> list = userMapper.selectByExample(example); System.out.println(list.size()); } @Test public void testSelectByPrimaryKey() { // 获取Mapper UserMapper userMapper = this.context.getBean(UserMapper.class); User user = userMapper.selectByPrimaryKey(1); System.out.println(user); } }
注意:
1. 逆向工程生成的代码只能做单表查询
2. 不能在生成的代码上进行扩展,因为如果数据库变更,需要重新使用逆向工程生成代码,原来编写的代码就被覆盖了。
3. 一张表会生成4个文件