主题
Mybatis框架快速入门
1、添加坐标
xml
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>2、编写实体类、持久层接口
3、编写持久层接口的映射文件xml
名称 :必须以持久层接口名称命名文件名,扩展名是.xml
持久层映射配置中 mapper 标签的 namespace 属性取值必须是持久层接口的全限定类名
SQL 语句的配置标签 <select>,<insert>,<delete>,<update> 的 id 属性必须和持久层接口的方法名相同。
4、编写 SqlMapConfig.xml 配置文件
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>
<!-- 配置 mybatis 的环境 -->
<environments default="mysql">
<!-- 配置 mysql 的环境 -->
<environment id="mysql">
<!-- 配置事务的类型 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置连接数据库的信息:用的是数据源(连接池) -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/ee50"/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
</dataSource>
</environment>
</environments>
<!-- 告知 mybatis 映射配置的位置 -->
<mappers>
<mapper resource="com/fan/dao/IUserDao.xml"/>
</mappers>
</configuration>5、测试代码
java
//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();注解版
1、在持久层接口中添加注解
java
@Select("select * from user")
List<User> findAll();2、编写 SqlMapConfig.xml 配置文件
xml
<!-- 告知 mybatis 映射配置的位置 -->
<mappers>
<mapper class="com.fan.dao.IUserDao"/>
</mappers>注意事项:在使用基于注解的 Mybatis 配置时,请移除 xml 的映射配置(IUserDao.xml)。
基于代理 Dao 实现 CRUD 操作
根据 ID 查询
在持久层接口中添加 findById 方法
java
User findById(Integer userId);在用户的映射配置文件中配置
xml
<!-- 根据 id 查询 -->
<select id="findById" resultType="com.fan.domain.User" parameterType="int">
select * from user where id = #{uid}
</select>resultType 属性:用于指定结果集的类型。
parameterType 属性:用于指定传入参数的类型。
sql 语句中使用#{}字符:
它代表占位符, 相当于原来 jdbc 部分所学的?,都是用于执行语句时替换实际的数据。
具体的数据是由#{}里面的内容决定的。
#{}中内容的写法:
由于数据类型是基本类型,所以此处可以随意写。
在测试类添加测试
java
public class MybastisCRUDTest {
private InputStream in ;
private SqlSessionFactory factory;
private SqlSession session;
private IUserDao userDao;
@Test
public void testFindOne() {
//6.执行操作
User user = userDao.findById(41);
System.out.println(user);
}
@Before//在测试方法执行之前执行
public void init()throws Exception {
//1.读取配置文件
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建构建者对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//3.创建 SqlSession 工厂对象
factory = builder.build(in);
//4.创建 SqlSession 对象
session = factory.openSession();
//5.创建 Dao 的代理对象
userDao = session.getMapper(IUserDao.class);
}
@After//在测试方法执行完成之后执行
public void destroy() throws Exception{
session.commit();
//7.释放资源
session.close();
in.close();
}
}保存操作
在持久层接口中添加新增方法
java
int saveUser(User user);在用户的映射配置文件中配置
xml
<!-- 保存用户-->
<insert id="saveUser" parameterType="com.fan.domain.User">
insert into user(username,birthday,sex,address)
values(#{username},#{birthday},#{sex},#{address})
</insert>parameterType 属性:
代表参数的类型,因为我们要传入的是一个类的对象,所以类型就写类的全名称。
sql 语句中使用#{}字符:
它代表占位符, 相当于原来 jdbc 部分所学的?,都是用于执行语句时替换实际的数据。
具体的数据是由#{}里面的内容决定的。
#{}中内容的写法:
由于我们保存方法的参数是 一个 User 对象,此处要写 User 对象中的属性名称。
它用的是 ognl 表达式。
ognl 表达式:
它是 apache 提供的一种表达式语言, 全称是:Object Graphic Navigation Language 对象图导航语言
它是按照一定的语法格式来获取数据的。
语法格式就是使用 #{对象.对象}的方式 #{user.username}它会先去找 user 对象,然后在 user 对象中找到 username 属性,并调用getUsername()方法把值取出来。但是我们在 parameterType 属性上指定了实体类名称,所以可以省略 user. 而直接写 username。
在实现增删改时一定要去控制事务的提交
java
@After//在测试方法执行完成之后执行
public void destroy() throws Exception{
//可以使用 session.commit() 来实现事务提交。
session.commit();
//7.释放资源
session.close();
in.close();
}获取新增用户 id 的返回值
xml
<insert id="saveUser" parameterType="USER">
<!-- 配置保存时获取插入的 id -->
<selectKey keyColumn="id" keyProperty="id" resultType="int">
select last_insert_id();
</selectKey>
insert into user(username,birthday,sex,address)
values(#{username},#{birthday},#{sex},#{address})
</insert>用户更新
在持久层接口中添加更新方法
java
int updateUser(User user);在用户的映射配置文件中配置
xml
<!-- 更新用户 -->
<update id="updateUser" parameterType="com.fan.domain.User">
update user set username=#{username},birthday=#{birthday},sex=#{sex},
address=#{address} where id=#{id}
</update>用户删除
在持久层接口中添加删除方法
java
int deleteUser(Integer userId);在用户的映射配置文件中配置
xml
<!-- 删除用户 -->
<delete id="deleteUser" parameterType="java.lang.Integer">
delete from user where id = #{uid}
</delete>用户模糊查询
在持久层接口中添加模糊查询方法
java
List<User> findByName(String username);在用户的映射配置文件中配置
xml
<!-- 根据名称模糊查询 -->
<select id="findByName" resultType="com.fan.domain.User" parameterType="String">
select * from user where username like #{username}
</select>测试方法
java
List<User> users = userDao.findByName("%王%");模糊查询的另一种配置方式
xml
<!-- 根据名称模糊查询 -->
<select id="findByName" parameterType="string" resultType="com.fan.domain.User">
select * from user where username like '%${value}%'
</select>我们在上面将原来的#{}占位符,改成了$ {value}。注意如果用模糊查询的这种写法,那么 ${value}的写法就是固定的,不能写成其它名字。
测试方法
java
List<User> users = userDao.findByName("王");MyBatis 中 #{}和${}的区别是什么?
#{}表示一个占位符号
通过#{}可以实现 preparedStatement 向占位符中设置值,自动进行 java 类型和 jdbc 类型转换,#{}可以有效防止 sql 注入。 #{}可以接收简单类型值或 pojo 属性值。 如果 parameterType 传输单个简单类型值, #{}括号中可以是 value 或其它名称。
${}表示拼接 sql 串
通过${}可以将 parameterType 传入的内容拼接在 sql 中且不进行 jdbc 类型转换, ${}可以接收简单类型值或 pojo 属性值,如果 parameterType 传输单个简单类型值, ${}括号中只能是 value。
查询使用聚合函数
在持久层接口中添加模糊查询方法
java
int findTotal();在用户的映射配置文件中配置
xml
<!-- 查询总记录条数 -->
<select id="findTotal" resultType="int">
select count(*) from user;
</select>Mybatis 的参数
parameterType
基本类型和String我们可以直接写类型名称, 也可以使用包名.类名的方式, 例如:java.lang.String。
实体类类型,目前我们只能使用全限定类名。
究其原因,是 mybaits 在加载时已经把常用的数据类型注册了别名,从而我们在使用时可以不写包名,而我们的是实体类并没有注册别名,所以必须写全限定类名。
resultType
resultType 属性可以指定结果集的类型,它支持基本类型和实体类类型。
它和 parameterType 一样,如果注册过类型别名的,可以直接使用别名。没有注册过的必须使用全限定类名。
resultMap
resultMap 标签可以建立查询的列名和实体类的属性名称不一致时建立对应关系。从而实现封装。
在 select 标签中使用 resultMap 属性指定引用即可。同时 resultMap 可以实现将查询结果映射为复杂类型的 pojo,比如在查询结果映射对象中包括 pojo 和 list 实现一对一查询和一对多查询。
xml
<!-- 建立 User 实体和数据库表的对应关系
type 属性:指定实体类的全限定类名
id 属性:给定一个唯一标识,是给查询 select 标签引用用的。
-->
<resultMap type="com.fan.domain.User" id="userMap">
<id column="id" property="userId"/>
<result column="username" property="userName"/>
<result column="sex" property="userSex"/>
<result column="address" property="userAddress"/>
<result column="birthday" property="userBirthday"/>
</resultMap>
<!--
id 标签:用于指定主键字段
result 标签:用于指定非主键字段
column 属性:用于指定数据库列名
property 属性:用于指定实体类属性名称
-->映射配置
xml
<!-- 配置查询所有操作 -->
<select id="findAll" resultMap="userMap">
select * from user
</select>SqlMapConfig.xml配置文件
SqlMapConfig.xml 中配置的内容和顺序
plain
-properties(属性)
--property
-settings(全局配置参数)
--setting
-typeAliases(类型别名)
--typeAliase
--package
-typeHandlers(类型处理器)
-objectFactory(对象工厂)
-plugins(插件)
-environments(环境集合属性对象)
--environment(环境子属性对象)
---transactionManager(事务管理)
---dataSource(数据源)
-mappers(映射器)
--mapper
--package在使用 properties 标签配置时,我们可以采用两种方式指定属性配置。
第一种
xml
<properties>
<property name="jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="jdbc.url" value="jdbc:mysql://localhost:3306/eesy"/>
<property name="jdbc.username" value="root"/>
<property name="jdbc.password" value="1234"/>
</properties>第二种,在 classpath 下定义 db.properties 文件
xml
<!-- properties 标签配置
配置连接数据库的信息
resource 属性:用于指定 properties 配置文件的位置,要求配置文件必须在类路径下
resource="jdbcConfig.properties"
url 属性:
URL: Uniform Resource Locator 统一资源定位符
http://localhost:8080/mystroe/CategoryServlet URL
协议 主机 端口 URI
URI: Uniform Resource Identifier 统一资源标识符
/mystroe/CategoryServlet
它是可以在 web 应用中唯一定位一个资源的路径
-->
<properties url=file:///D:/IdeaProjects/day02_eesy_01mybatisCRUD/src/main/resources/jdbcConfig.properties>
</properties>properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/eesy
jdbc.username=root
jdbc.password=1234xml
<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>typeAliases(类型别名)
xml
<typeAliases>
<!-- 单个别名定义 -->
<typeAlias alias="user" type="com.fan.domain.User"/>
<!-- 批量别名定义,扫描整个包下的类,别名为类名(首字母大写或小写都可以) -->
<package name="com.fan.domain"/>
<package name="其它包"/>
</typeAliases>mappers(映射器)
xml
使用相对于类路径的资源
如: <mapper resource="com/fan/dao/IUserDao.xml" />xml
使用 mapper 接口类路径
如: <mapper class="com.fan.dao.UserDao"/>
注意:此种方法要求 mapper 接口名称和 mapper 映射文件名称相同,且放在同一个目录中。xml
注册指定包下的所有 mapper 接口
如: <package name="cn.itcast.mybatis.mapper"/>
注意:此种方法要求 mapper 接口名称和 mapper 映射文件名称相同,且放在同一个目录中。Mybatis 中数据源的配置
xml
我们的数据源配置就是在 SqlMapConfig.xml 文件中, 具体配置如下:
<!-- 配置数据源(连接池)信息 -->
<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>
MyBatis 在初始化时, 根据<dataSource>的 type 属性来创建相应类型的的数据源 DataSource,即:
type=”POOLED”: MyBatis 会创建 PooledDataSource 实例
type=”UNPOOLED” : MyBatis 会创建 UnpooledDataSource 实例
type=”JNDI”: MyBatis 会从 JNDI 服务上查找 DataSource 实例,然后返回使用Mybatis 的动态 SQL 语句
动态 SQL 之<if>标签
持久层 Dao 接口
java
List<User> findByUser(User user);持久层 Dao 映射配置
xml
<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>
注意: <if>标签的 test 属性中写的是对象的属性名,如果是包装类的对象要使用 OGNL 表达式的写法。
另外要注意 where 1=1 的作用~!动态 SQL 之<where>标签
为了简化上面 where 1=1 的条件拼装,我们可以采用标签来简化开发。
xml
<!-- 根据用户信息查询 -->
<select id="findByUser" resultType="user" parameterType="user">
<include refid="defaultSql"></include>
<where>
<if test="username!=null and username != '' ">
and username like #{username}
</if>
<if test="address != null">
and address like #{address}
</if>
</where>
</select>动态标签之<foreach>标签
需求
传入多个 id 查询用户信息,用下边两个 sql 实现:
SELECT * FROM USERS WHERE username LIKE '%张%' AND (id =10 OR id =89 OR id=16)
SELECT * FROM USERS WHERE username LIKE '%张%' AND id IN (10,89,16)
这样我们在进行范围查询时,就要将一个集合中的值,作为参数动态添加进来。
这样我们将如何进行参数的传递?
在 QueryVo 中加入一个 List 集合用于封装参数
java
public class QueryVo implements Serializable {
private List<Integer> ids;
public List<Integer> getIds() {
return ids;
}
public void setIds(List<Integer> ids) {
this.ids = ids;
}
}持久层 Dao 接口
java
List<User> findInIds(QueryVo vo);持久层 Dao 映射配置
xml
<!-- 查询所有用户在 id 的集合之中 -->
<select id="findInIds" resultType="user" parameterType="queryvo">
<!-- select * from user where id in (1,2,3,4,5); -->
<include refid="defaultSql"></include>
<where>
<if test="ids != null and ids.size() > 0">
<foreach collection="ids" open="id in ( " close=")" item="uid"
separator=",">
#{uid}
</foreach>
</if>
</where>
</select>
SQL 语句:
select 字段 from user where id in (?)
<foreach>标签用于遍历集合,它的属性:
collection:代表要遍历的集合元素,注意编写时不要写#{}
open:代表语句的开始部分
close:代表结束部分
item:代表遍历集合的每个元素,生成的变量名
sperator:代表分隔符Mybatis 中简化编写的 SQL 片段
定义代码片段
xml
<!-- 抽取重复的语句代码片段 -->
<sql id="defaultSql">
select * from user
</sql>引用代码片段
xml
<!-- 配置查询所有操作 -->
<select id="findAll" resultType="user">
<include refid="defaultSql"></include>
</select>
<!-- 根据 id 查询 -->
<select id="findById" resultType="UsEr" parameterType="int">
<include refid="defaultSql"></include>
where id = #{uid}
</select>Mybatis 多表查询之一对多
方式一
定义专门的 po 类作为输出类型,其中定义了 sql 查询结果集所有的字段。此方法较为简单,企业中使用普遍。
编写 Sql 语句
sql
SELECT
account.*,
user.username,
user.address
FROM
account,
user
WHERE account.uid = user.id定义 AccountUser 类
为了能够封装上面 SQL 语句的查询结果,定义 AccountCustomer 类中要包含账户信息同时还要包含用户信
息,所以我们要在定义 AccountUser 类时可以继承 User 类。
定义账户的持久层 Dao 接口
java
//查询所有账户,同时获取账户的所属用户名称以及它的地址信息
List<AccountUser> findAll();定义 AccountDao.xml 文件中的查询配置信息
xml
<mapper namespace="com.fan.dao.IAccountDao">
<!-- 配置查询所有操作-->
<select id="findAll" resultType="accountuser">
select a.*,u.username,u.address from account a,user u where a.uid =u.id;
</select>
</mapper>
注意:因为上面查询的结果中包含了账户信息同时还包含了用户信息,所以我们的返回值类型 returnType
的值设置为 AccountUser 类型,这样就可以接收账户信息和用户信息了。方式二
使用 resultMap,定义专门的 resultMap 用于映射一对一查询结果。
通过面向对象的(has a)关系可以得知,我们可以在 Account 类中加入一个 User 类的对象来代表这个账户是哪个用户的。
修改 Account 类
在 Account 类中加入 User 类的对象作为 Account 类的一个属性。
定义 AccountDao.xml 文件
xml
<mapper namespace="com.fan.dao.IAccountDao">
<!-- 建立对应关系 -->
<resultMap type="account" id="accountMap">
<id column="aid" property="id"/>
<result column="uid" property="uid"/>
<result column="money" property="money"/>
<!-- 它是用于指定从表方的引用实体属性的 -->
<association property="user" javaType="user">
<id column="id" property="id"/>
<result column="username" property="username"/>
<result column="sex" property="sex"/>
<result column="birthday" property="birthday"/>
<result column="address" property="address"/>
</association>
</resultMap>
<select id="findAll" resultMap="accountMap">
select u.*,a.id as aid,a.uid,a.money from account a,user u where a.uid =u.id;
</select>
</mapper>一对多查询
编写 SQL 语句
sql
SELECT
u.*, acc.id id,
acc.uid,
acc.money
FROM
user u
LEFT JOIN account acc ON u.id = acc.uidUser 类加入 List<Account>
java
private List<Account> accounts;用户持久层 Dao 接口中加入查询方法
xml
<mapper namespace="com.fan.dao.IUserDao">
<resultMap type="user" id="userMap">
<id column="id" property="id"></id>
<result column="username" property="username"/>
<result column="address" property="address"/>
<result column="sex" property="sex"/>
<result column="birthday" property="birthday"/>
<!-- collection 是用于建立一对多中集合属性的对应关系
ofType 用于指定集合元素的数据类型
-->
<collection property="accounts" ofType="account">
<id column="aid" property="id"/>
<result column="uid" property="uid"/>
<result column="money" property="money"/>
</collection>
</resultMap>
<!-- 配置查询所有操作 -->
<select id="findAll" resultMap="userMap">
select u.*,a.id as aid ,a.uid,a.money from user u left outer join account
on u.id =a.uid
</select>
</mapper>
collection
部分定义了用户关联的账户信息。表示关联查询结果集
property="accList":
关联查询的结果集存储在 User 对象的上哪个属性。
ofType="account":
指定关联查询的结果集中的对象类型即List中的对象类型。此处可以使用别名,也可以使用全限定名。多对多查询
SQL语句
sql
SELECT
r.*,u.id uid,
u.username username,
u.birthday birthday,
u.sex sex,
u.address address
FROM
ROLE r
INNER JOIN
USER_ROLE ur
ON ( r.id = ur.rid)
INNER JOIN
USER u
ON (ur.uid = u.id);编写角色实体类
java
public class Role implements Serializable {
private Integer roleId;
private String roleName;
private String roleDesc;
//多对多的关系映射:一个角色可以赋予多个用户
private List<User> users;
}编写 Role 持久层接口
java
List<Role> findAll();编写映射文件
xml
<mapper namespace="com.fan.dao.IRoleDao">
<!--定义 role 表的 ResultMap-->
<resultMap id="roleMap" type="role">
<id property="roleId" column="rid"></id>
<result property="roleName" column="role_name"></result>
<result property="roleDesc" column="role_desc"></result>
<collection property="users" ofType="user">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="address" property="address"></result>
<result column="sex" property="sex"></result>
<result column="birthday" property="birthday"></result>
</collection>
</resultMap>
<!--查询所有-->
<select id="findAll" resultMap="roleMap">
select u.*,r.id as rid,r.role_name,r.role_desc from role r
left outer join user_role ur on r.id = ur.rid
left outer join user u on u.id = ur.uid
</select>
</mapper>Mybatis 延迟加载策略
延迟加载:
就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载.
好处: 先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。
坏处:因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时间,所以可能造成用户等待时间变长,造成用户体验下降。
通过 association、 collection 实现一对一及一对多映射。 association、 collection 具备延迟加载功能。
xml
<!-- 开启延迟加载的支持 -->
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>账户的持久层映射文件
xml
<mapper namespace="com.fan.dao.IAccountDao">
<!-- 建立对应关系 -->
<resultMap type="account" id="accountMap">
<id column="aid" property="id"/>
<result column="uid" property="uid"/>
<result column="money" property="money"/>
<!-- 它是用于指定从表方的引用实体属性的 -->
<association property="user" javaType="user"
select="com.fan.dao.IUserDao.findById"
column="uid">
</association>
</resultMap>
<select id="findAll" resultMap="accountMap">
select * from account
</select>
</mapper>
select: 填写我们要调用的 select 映射的 id
column : 填写我们要传递给 select 映射的参数用户的持久层接口和映射文件
java
User findById(Integer userId);xml
<mapper namespace="com.fan.dao.IUserDao">
<!-- 根据 id 查询 -->
<select id="findById" resultType="user" parameterType="int" >
select * from user where id = #{uid}
</select>
</mapper>懒加载:只查账户信息不查用户信息
使用 Collection 实现延迟加载
同样我们也可以在一对多关系配置的<collection>结点中配置延迟加载策略。
<collection>结点中也有 select 属性, column 属性
编写用户和账户持久层接口的方法
java
List<User> findAll();xml
<resultMap type="user" id="userMap">
<id column="id" property="id"></id>
<result column="username" property="username"/>
<result column="address" property="address"/>
<result column="sex" property="sex"/>
<result column="birthday" property="birthday"/>
<!-- collection 是用于建立一对多中集合属性的对应关系
ofType 用于指定集合元素的数据类型
select 是用于指定查询账户的唯一标识(账户的 dao 全限定类名加上方法名称)
column 是用于指定使用哪个字段的值作为条件查询
-->
<collection property="accounts" ofType="account"
select="com.fan.dao.IAccountDao.findByUid"
column="id">
</collection>
</resultMap>
<!-- 配置查询所有操作 -->
<select id="findAll" resultMap="userMap">
select * from user
</select>
<collection>标签:
主要用于加载关联的集合对象
select 属性:
用于指定查询 account 列表的 sql 语句,所以填写的是该 sql 映射的 id
column 属性:
用于指定 select 属性的 sql 语句的参数来源,上面的参数来自于 user 的 id 列,所以就写成 id 这一个字段名了编写账户持久层映射配置
xml
<!-- 根据用户 id 查询账户信息 -->
<select id="findByUid" resultType="account" parameterType="int">
select * from account where uid = #{uid}
</select>Mybatis 缓存
Mybatis 一级缓存
一级缓存是 SqlSession 范围的缓存,当调用 SqlSession 的修改,添加,删除, commit(), close()等方法时,就会清空一级缓存。
Mybatis 二级缓存
二级缓存是 mapper 映射级别的缓存,多个 SqlSession 去操作同一个 Mapper 映射的 sql 语句,多个SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession 的。
二级缓存的开启与关闭
第一步:在 SqlMapConfig.xml 文件开启二级缓存
xml
<settings>
<!-- 开启二级缓存的支持 -->
<setting name="cacheEnabled" value="true"/>
</settings>
因为 cacheEnabled 的取值默认就为 true,所以这一步可以省略不配置。为 true 代表开启二级缓存;为
false 代表不开启二级缓存。第二步:配置相关的 Mapper 映射文件
xml
<mapper namespace="com.fan.dao.IUserDao">
<!-- 开启二级缓存的支持 -->
<cache></cache>
</mapper>第三步: 配置 statement 上面的 useCache 属性
xml
<!-- 根据 id 查询 -->
<select id="findById" resultType="user" parameterType="int" useCache="true">
select * from user where id = #{uid}
</select>
将 UserDao.xml 映射文件中的<select>标签中设置 useCache=”true”代表当前这个 statement 要使用
二级缓存,如果不使用二级缓存可以设置为 false。
注意: 针对每次查询都需要最新的数据 sql,要设置成 useCache=false,禁用二级缓存。mybatis 的常用注解说明
@Insert: 实现新增
@Update: 实现更新
@Delete: 实现删除
@Select: 实现查询
@Result: 实现结果集封装
@Results:可以与@Result 一起使用,封装多个结果集
@ResultMap:实现引用@Results定义的封装
@One:实现一对一结果集封装
@Many:实现一对多结果集封装
@SelectProvider: 实现动态 SQL 映射
@CacheNamespace:实现注解二级缓存的使用
使用 Mybatis 注解实现基本 CRUD
java
/**
* 查询所有用户
* @return
*/
@Select("select * from user")
@Results(id="userMap",
value= {
@Result(id=true,column="id",property="userId"),
@Result(column="username",property="userName"),
@Result(column="sex",property="userSex"),
@Result(column="address",property="userAddress"),
@Result(column="birthday",property="userBirthday")
})
List<User> findAll();
/**
* 根据 id 查询一个用户
* @param userId
* @return
*/
@Select("select * from user where id = #{uid} ")
@ResultMap("userMap")
User findById(Integer userId);
/**
* 保存操作
* @param user
* @return
*/
@Insert("insert into
user(username,sex,birthday,address)values(#{username},#{sex},#{birthday},#{address}
)")
@SelectKey(keyColumn="id",keyProperty="id",resultType=Integer.class,before =
false, statement = { "select last_insert_id()" })
int saveUser(User user);
/**
* 更新操作
* @param user
* @return
*/
@Update("update user set
username=#{username},address=#{address},sex=#{sex},birthday=#{birthday} where id
=#{id} ")
int updateUser(User user);
/**
* 删除用户
* @param userId
* @return
*/
@Delete("delete from user where id = #{uid} ")
int deleteUser(Integer userId);
/**
* 查询使用聚合函数
* @return
*/
@Select("select count(*) from user ")
int findTotal();
/**
* 模糊查询
* @param name
* @return
*/
@Select("select * from user where username like #{username} ")
List<User> findByName(String name);通过注解方式,我们就不需要再去编写 UserDao.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>
<!-- 配置 properties 文件的位置 -->
<properties resource="jdbcConfig.properties"></properties>
<!-- 配置别名的注册 -->
<typeAliases>
<package name="com.fan.domain"/>
</typeAliases>
<!-- 配置环境 -->
<environments default="mysql">
<!-- 配置 mysql 的环境 -->
<environment id="mysql">
<!-- 配置事务的类型是 JDBC -->
<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>
<!-- 配置 dao 接口的位置,它有两种方式
第一种:使用 mapper 标签配置 class 属性
第二种:使用 package 标签,直接指定 dao 接口所在的包
-->
<package name="com.fan.dao"/>
</mappers>
</configuration>使用注解实现复杂关系映射开发
plain
@Results 注解
代替的是标签<resultMap>
该注解中可以使用单个@Result 注解,也可以使用@Result 集合
@Results({@Result(), @Result() })或@Results(@Result())
@Resutl 注解
代替了 <id>标签和<result>标签
@Result 中 属性介绍:
id 是否是主键字段
column 数据库的列名
property 需要装配的属性名
one 需要使用的@One 注解(@Result(one=@One)()))
many 需要使用的@Many 注解(@Result(many=@many)()))
@One 注解(一对一)
代替了<assocation>标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。
@One 注解属性介绍:
select 指定用来多表查询的 sqlmapper
fetchType 会覆盖全局的配置参数 lazyLoadingEnabled。。
使用格式:
@Result(column=" ",property="",one=@One(select=""))
@Many 注解(多对一)
代替了<Collection>标签,是是多表查询的关键,在注解中用来指定子查询返回对象集合。
注意:聚集元素用来处理“一对多”的关系。需要指定映射的 Java 实体类的属性,属性的 javaType
(一般为 ArrayList)但是注解中可以不定义;
使用格式:
@Result(property="",column="",many=@Many(select=""))使用注解实现一对一复杂关系映射及延迟加载
java
@Select("select * from account")
@Results(id="accountMap",
value= {
@Result(id=true,column="id",property="id"),
@Result(column="uid",property="uid"),
@Result(column="money",property="money"),
@Result(column="uid",
property="user",
one=@One(select="com.fan.dao.IUserDao.findById",
fetchType=FetchType.LAZY)
)
})
List<Account> findAll();使用注解实现一对多复杂关系映射
java
@Select("select * from user")
@Results(id="userMap",
value= {
@Result(id=true,column="id",property="userId"),
@Result(column="username",property="userName"),
@Result(column="sex",property="userSex"),
@Result(column="address",property="userAddress"),
@Result(column="birthday",property="userBirthday"),
@Result(column="id",property="accounts",
many=@Many(
select="com.fan.dao.IAccountDao.findByUid"
fetchType=FetchType.LAZY
)
)
})
List<User> findAll();
@Many:
相当于<collection>的配置
select 属性:代表将要执行的 sql 语句
fetchType 属性:代表加载方式,一般如果要延迟加载都设置为 LAZY 的值mybatis 基于注解的二级缓存
在 SqlMapConfig 中开启二级缓存支持
xml
<!-- 配置二级缓存 -->
<settings>
<!-- 开启二级缓存的支持 -->
<setting name="cacheEnabled" value="true"/>
</settings>在持久层接口中使用注解配置二级缓存
java
@CacheNamespace(blocking=true)//mybatis 基于注解方式实现配置二级缓存
public interface IUserDao {}