Mybatis框架

一个解决数据的持久化问题的框架.

Mybatis框架的快速入门

  1. 创建数据库
  2. 创建Maven工程,在pom.xml文件中添加mybatis坐标.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
</dependencies>
  1. 编写user类,注意:user类中的变量与数据库中的列名保持一致
  2. 编写持久层接口UserDao
  3. 编写UserDao接口的映射文件Mapper.xml
  4. 编写配置文件MapConfig.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?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">
<!--Mybatis的配置文件-->
<configuration>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=GMT"/>
<property name="username" value="root"/>
<property name="password" value="xby123456"/>
</dataSource>
</environment>
</environments>


<mappers>
<!--<mapper resource="mapper.xml"/>-->
<mapper resource="mapper.xml"/>
</mappers>
</configuration>
  1. 编写测试类,测试.

在使用Mybatis时

  1. //1.读取配置文件
  2. //2.创建SqlSessionFactory的构建者对象
  3. //3.使用构建者创建工厂对象SqlSessionFactory
  4. //4.使用SqlSessionFactory生产SqlSession对象
  5. //5.使用SqlSession创建dao接口的代理对象
  6. //6.使用代理对象执行查询所有方法
  7. //7.释放资源

代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//1.读取配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建 SqlSessionFactory 的构建者对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//3.使用构建者创建工厂对象 SqlSessionFactory
SqlSessionFactory factory = builder.build(in);
//4.使用 SqlSessionFactory 生产 SqlSession 对象
SqlSession session = factory.openSession();
//5.使用 SqlSession 创建 dao 接口的代理对象
IUserDao userDao = session.getMapper(IUserDao.class);
//6.使用代理对象执行查询所有方法
List<User> users = userDao.findAll();
for(User user : users) {
System.out.println(user);
}
//7.释放资源
session.close();
in.close();
}

Mybatis实现CURD操作

  1. 在接口中定义方法
  2. 在mapper.xml文件中使用标签将方法与sql语句的映射关系建立起来.

在标签中,id是方法名称,parameterType是传入参数类别,在返回参数中,当类的名称与数据库列名一一相对的时候,resultType就是返回数据类型,否则,使用resultMap来将类中的变量与数据库中的列名对应,再使用resultMap来设定返回类型.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<select id="findAll" resultType="doMain.user">
select * from users;
</select>

<insert id="saveUser" parameterType="doMain.user">
insert into users(id,username,sex,address) values(#{id},#{username},#{sex},#{address});
</insert>

<update id="updateUser" parameterType="doMain.user">
update users set username=#{username},sex=#{sex},address=#{address} where id=#{id};
</update>

<delete id="deleteUser" parameterType="int">
delete from users where id=#{id};
</delete>
  1. 测试类中测试方法.

保存操作中的获取返回的自动增长key

在保存操作中,某些键会被设置自动增长,插入成功后,若要正确返回自增的id值,只需要在mapper配置selectKey标签即可

1
2
3
4
<insert id="saveUser" parameterType="doMain.user">
<selectKey keyProperty="id" keyColumn="id" resultType="doMain.user" order="AFTER"></selectKey>
insert into users(id,username,sex,address) values(#{id},#{username},#{sex},#{address});
</insert>

其中, keyProperty是类中id名 keyColumn 是数据库中的列名 resultType 是返回类型 order是使用世纪,after表示操作之后再执行.

CURD的sql语句的preparedStatement语句写法

在需要使用preparedStatement语句时,mapper.xml中特殊的办法是:

多变量,如保存一个用户的数据

修改一个数据

1
2
3
4
5
6
7
<insert id="saveUser" parameterType="doMain.user">
insert into users(id,username,sex,address) values(#{id},#{username},#{sex},#{address});
</insert>

<update id="updateUser" parameterType="doMain.user">
update users set id=#{id},username=#{username},sex=#{sex},address=#{address} where id=#{id};
</update>

单变量

1
2
3
<delete id="deleteUser" parameterType="int">
delete from users where id=#{uid};
</delete>

关于#{}:

在Mybatis的mapper.xml文件中,当parameterType是一个具体类时,#{}中的要填写正确的类中的变量名,但如果,parameterType传入的具体的基本变量类型时,#{}就相当于平时jdbc中的占位符?,可以随意填写.

关于properties和typeAlias标签的使用

properties标签用于引入外部文件或提前定义信息

如:在mapperConfig.xml文件中我们可以引入外部的jdbc文件来动态获取mysql的配置.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<configuration>
<!-- 引入外部的jdbc配置文件-->
<properties resource="jdbc.properties"></properties>

<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"></transactionManager>
<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>

typeAlias标签用于起别名

标签使用,type属性为被定义的类,alias属性为起的别名,当配置完成后,别名也能当作全限定类名来使用.

1
2
3
4
<typeAliases>
<typeAlias type="Dao.AccountDao" alias="AccountDao"></typeAlias>
<typeAlias type="Dao.UserDao" alias="UserDao"></typeAlias>
</typeAliases>
Mybatis中的模糊查询
1
2
3
<select id="findUserByName" parameterType="string" resultType="doMain.user">
select * from users where username like #{uname};
</select>

这样填写时,传入的参数要在两边拼接上%号查询.

模糊查询的另一种配置方式

1
2
3
<select id="findByName" parameterType="string" resultType="com.itheima.domain.User">
select * from user where username like '%${value}%'
</select>

此时,传入的数据不需要拼接就可以正常查询出来了.

#{}与${}的区别

1
2
3
4
5
6
7
#{}表示一个占位符号
通过#{}可以实现 preparedStatement 向占位符中设置值,自动进行 java 类型和 jdbc 类型转换,
#{}可以有效防止 sql 注入。 #{}可以接收简单类型值或 pojo 属性值。 如果 parameterType 传输单个简单类
型值,#{}括号中可以是 value 或其它名称。
${}表示拼接 sql 串
通过${}可以将 parameterType 传入的内容拼接在 sql 中且不进行 jdbc 类型转换, ${}可以接收简
单类型值或 pojo 属性值,如果 parameterType 传输单个简单类型值,${}括号中只能是 value。

实现类中变量名与数据库列名不对应时的解决办法(resultMap)

当实现类中的变量名与数据库的列名不是对应时,可以使用两种方法

  1. 起别名,即使用as,但该方法繁琐.
  2. 使用resultMap,建立一个变量名与数据库列名的映射

此时若有变量id,name,sex,birthday,但数据库列名分别位:Uid,Uname,Usex,Ubirthday,在mapper.xml配置文件中添加以下信息.

1
2
3
4
5
6
<resultMap type="doMain.user" id="userMap">
<id property="id" column="Uid"/>
<result property="name" column="Uname"/>
<result property="sex" column="Usex"/>
<result property="birthday" column="Ubirthday"/>
</resultMap>

此时,数据库列名与变量名的映射就建立了起来.type属性表明该resultMap中的变量为doMain.user类中的,id属性为起的一个名称,在调用时,使用该id.标签内,id属性表示主键,其余result属性表示其他变量与列的映射关系.

Mybatis中的连接池

连接池分类

连接池分两类,为unpooled与pooled
1.unpooled连接池原理

JDBC修改自动提交事务

仅需要在创建Session对象时传入参数true即可

Mybatis 中事务的提交方式,本质上就是调用 JDBC 的 setAutoCommit()来实现事务控制,openSession方法有很多的重载方法.使用的该方法调用JDBC的setAutoCommit(),传入true,就开启了自动提交事务.

Mybatis的动态SQL语句

在mapper.xml配置文件中的select标签下可以添加if,where标签.

  1. if标签:必要属性 test

if标签用来判断一些传入参数,当参数满足条件,作为条件进行查询.

1
2
3
4
5
6
7
8
9
<select id="findByUser" resultType="user" parameterType="user">
select * from user where 1=1
<if test="username!=null and username != '' ">
and username like #{username}
</if>
<if test="address != null">
and address like #{address}
</if>
</select>

此处的1=1仅仅是一个占位符,在下面的if语句满足后进行替换.

  1. where标签,用来替换sql语句中的where与占位符
1
2
3
4
5
6
7
8
9
10
11
<select id="moveFind" resultType="doMain.user" parameterType="doMain.user">
select * from users
<where>
<if test="username!=null ">
username like #{username};
</if>
<if test="address!=null">
address =#{address};
</if>
</where>
</select>
  1. foreach标签
    对一个集合中的元素循环取出,然后查询.

在这里新建了一个queryVO类,类中有一个私有的List集合,向集合中添加元素,然后在以下代码中取出,查询.

1
2
3
4
5
6
7
8
9
10
<select id="findList" parameterType="doMain.queryVO" resultType="doMain.user">
select * from users
<where>
<if test="lists!=null and lists.size()>0">
<foreach collection="lists" open="id in ( " close=")" item="id" separator=",">
#{id}
</foreach>
</if>
</where>
</select>

标签中,collection属性表示要查询的变量,open表示语句开始处,close表示语句结束处,item表示要被查询的,即?=?中=号前面的那一项,separator表示分隔符,它表示了每一个元素取出后的排列分隔符.

取出就是这样(1,2,3,4) 用逗号将每一个集合中的元素分开.

Mybatis的多表查询

一对多 多表查询

Mybatis延迟加载

Mybatis缓存

一级缓存

只要sqlSession存在,即没有被close或flush时,一级缓存就存在,当第一次进行查询操作时,查询的结果就被存入了Mybatis的一级缓存,下一次查询时,会先在一级缓存中寻找,如果有就直接取出,没有就重新查询.当进行增加,删除,修改的操作并提交事务后,一级缓存就会被清空.

==sqlSession.clearCache()也可以清空缓存.==

二级缓存

多个sqlSession跨Session共同操作一片缓存区域.

二级缓存使用步骤:

  1. 二级缓存的开启/关闭

在mapperConfig.xml中加入

1
2
3
4
<settings>
<!-- 开启二级缓存的支持 -->
<setting name="cacheEnabled" value="true"/>
</settings>

因为 cacheEnabled 的取值默认就为 true,所以这一步可以省略不配置。为 true 代表开启二级缓存;为false 代表不开启二级缓存。

  1. 在mapper映射文件中使用标签配置
  2. 在需要使用二级缓存的方法上对userCache属性定位true
1
2
3
<select id="findAll" resultMap="AccountUserMap" useCache="true">
select account.*,user.username,user.address from account,user where user.id=account.uid
</select>

==针对每次查询都需要最新的数据 sql,要设置成 useCache=false,禁用二级缓存==

Mybatis注解开发

mapperConfig.xml配置中,在标签下配置接口所在路径

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?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">
<!--Mybatis的配置文件-->
<configuration>
<!-- 引入外部的jdbc配置文件-->
<properties resource="jdbc.properties"></properties>

<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"></transactionManager>
<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="xby.Dao"></package>
</mappers>
</configuration>

此时,不需要再使用mapper.xml来配置.

CURD操作

在接口中,方法名上使用注解(Select,Update,Insert,Delete)来配置

1
2
3
4
5
@Select("select * from user")
List<User> findAll();
@Insert("insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})")
@Options(useGeneratedKeys = true,keyProperty = "id",keyColumn = "id")
void saveUser(User user);

注解操作多表查询

注解解决类名与数据库表名不一致的问题

使用注解@Results

1
2
3
4
@Results(id = "map",value = {
@Result(id=true,property = "id",column = "id"),
@Result(property = "name",column = "username")
})

注解Results中,id为给对应关系的Results起一个名字,value中配置各属性对应的数据库表列名.Vlaue中,注解Result中的id为是否为主键,是则配置true,默认为false.

配置完毕后,在之后的方法注解中,就可以直接引用.

注解完成多表一对一查询

1
2
3
@Select("select * from account")
@Results(@Result(property = "user",column = "uid",one=@One(select = "xby.Dao.UserDao.findById",fetchType = FetchType.EAGER)))
List<Account> findAll();

此处,使用@Result注解,子注解Result可以配置多表查询,property代表本类中的变量名,column代表查询时的标记(数据库)

one=@One中,select代表查询方法(此处需要全限定类名),detchType代表延迟加载类型(EAGER为立即加载,LAZY为延迟加载).

注解方式完成多表一对多查询

主体查询方法:

1
2
3
4
5
6
7
8
9
10
11
@Select("select * from user")
@Results(id="userMap", value= {
@Result(id=true,property = "id",column = "id"),
@Result(property = "username",column = "username"),
@Result(property = "birthday",column = "birthday"),
@Result(property = "sex",column = "sex"),
@Result(property = "address",column = "address"),
@Result(property = "accounts", column = "id", many = @Many(select = "xby.Dao.AccountDao.findAccountByUid",
fetchType = FetchType.LAZY))
})
List<User> findAll();

一对多查询方法:

1
2
@Select("select * from account where uid=#{id}")
List<Account>findAccountByUid(int id);

延迟加载与立即加载的区别:

注解使用二级缓存

  1. 在mapperConfig.xml文件中配置
1
2
3
4
<settings>
<!-- 开启二级缓存的支持 -->
<setting name="cacheEnabled" value="true"/>
</settings>
  1. 在接口上使用注解@CacheNamespace

将其属性blocking设置为true,默认为false,此时就打开了二级缓存.