目录
Mybatis基础
概述:
- mybatis早期版本叫做ibatis,目前代码托管在github。
- mybatis是对jdbc的封装,是一个持久层的框架。
- mybatis是通过xml或者注解进行配置,实现java对象与sql语句的对应关系。(映射)
SqlMapConfig.xml 主配置
在项目的位置:
xml主配置文件的内容:
- 数据库连接配置。
- 数据库连接池、事务管理。
- 加载接口的映射。
使用mybatis内置数据库连接池的主配置示例:
<?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>
<!--environments配置环境数据库使用哪个连接-->
<environments default="mysql">
<!--配置具体连接到哪一个数据库-->
<environment id="mysql">
<!--transactionManager,配置事物控制类型为JDBC-->
<transactionManager type="JDBC"></transactionManager>
<!--配置数据库连接池
POOLED,mybatis内置的数据库连接池(推荐使用)
UNPOOLED,不使用连接池
JNDI,使用服务器tomcat容器的数据库连接池
-->
<dataSource type="POOLED">
<!--mysql驱动类-->
<property name="driver" value="com.mysql.jdbc.Driver"></property>
<!--数据库连接字符串-->
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf8"></property>
<!--username数据库用户名-->
<property name="username" value="root"></property>
<!--password数据库密码-->
<property name="password" value="root"></property>
</dataSource>
</environment>
</environments>
<!--关联接口映射配置文件-->
<mappers>
<!--映射com/itheima/dao/IUserDao.xml接口实现配置文件-->
<mapper resource="com/itheima/dao/IUserDao.xml"></mapper>
</mappers>
</configuration>
dao接口
位置:
代码:
public interface IUserDao {
List<User> findAll();
}
dao接口映射(XML)
配置文件名:
IUserDao.xml
- 也可以叫做UserDaoMapper.xml
配置文件的作用:
- myabits框架会根据这个映射文件对dao接口进行实现。所以这个配置文件相当于实现类。
映射文件位置:
1)创建在resource中,与java中的dao接口层级一样。
2)在resource创建多级目录的配置文件时,目录之前用 / ,不能用 .
配置文件的示例:
<?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名称空间,用于定义是哪个类的映射文件,这里需要写所映射接口的类全名-->
<mapper namespace="com.itheima.dao.IUserDao">
<select id="findAll" resultType="com.itheima.entity.User">
select * from user
</select>
</mapper>
参数说明:
- 标签类型写需要执行的操作。
- namespace:对应java接口的全路径,用于指明实现具体那个接口。
- id:用于指明实现哪个接口方法名字。
- parameterType:用于指明方法的参数类型。
- resultType:用于指明方法返回的类型
若类型是实体类,则写类全名。
- 例:com.itheima.entity.User
使用mybatis执行数据方法层方法获取结果:
前提:
- 引入日志文件log4j.properties
- 引入log4j依赖
代码:
public class UserDaoTest {
@Test
public void test1() throws IOException {
//使用mybatis执行数据方法层方法获取结果
//1.获取主配置文件的输入流(主配置配置会关联接口映射配置文件)
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//获取类路径下面的文件的输入流
//2.创建数据库连接工厂构建类
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
//3.根据数据库连接工厂构建类创建数据库连接工厂
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(in);
//4.根据数据库连接工厂获取数据库连接SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//5.根据SqlSession对象获取IUserDao映射代理类对象(动态代理对象class com.sun.proxy.$Proxy4)
IUserDao userDao = sqlSession.getMapper(IUserDao.class);
//6.执行实现类方法(执行数据库查询操作)
List<User> userList = userDao.findAll();
userList.forEach(System.out::println);
//关闭资源
//查询可以不用提交事务
sqlSession.commit();
sqlSession.close();
in.close();
}
}
注意事项:
1)获取主配置文件的输入流有两种方法:
1)当导入的Resources是属于javax.annotation时:
- inputStream in = Resources.class.getResourceAsStream("/sqlMapConfig.xml");
2)当导入的Resources是属于org.apache.ibatis.io时:(推荐)
- inputStream in = Resources.getResourceAsStream("sqlMapConfig.xml");
2)手动提交和自动提交:
1)手动提交
- 不需要任何设置,默认是手动提交。
- 执行对数据库的操作后,需要:sqlSession.commit();
2)自动提交
- 执行对数据库的操作后,不需要:sqlSession.commit();
- 需要在设置自动提交,在创建session对象时设置参数。
- Sqlsession sqlsession = sqlSessionFactory.openSession(true);
- 参数是设置是否设置自动提交事务,如果不设置默认是false。
ognl表达式
格式:
- #{对象的属性名}
作用:
- 相当于sql语句的占位符。
- 可以获取参数类型对象的数据,要求表达式里面的属性名与对象名必须完全一致。
作用范围:
在sql语句中。
- 在非sql语句中,不需要写ognl表达式。
resultType输出参数
注意事项:
- 若没有设置,默认返回影响的行数。
resultMap输出参数
出现问题:
- 通过resultType作为输出参数,可以把查询的结果,自动封装为对象,但是有要求:数据库中的列名称,要与对象的属性一致。否则不能正确封装数据。
解决方案:
- 使用resultMap:设置列与属性的映射关系,从而解决列与属性不一致时候不能正确封装数据的问题。
示例:
<resultMap id="userResultMap" type="com.itheima.entity.User">
<!--建立对象的唯一标记与表的主键映射关系-->
<id property="id" column="id_"></id>
<!--建立对象的其他属性与表的非主键字段的映射关系-->
<result property="username" column="username_"></result>
<result property="birthday" column="birthday_"></result>
<result property="sex" column="sex_"></result>
<result property="address" column="address_"></result>
</resultMap>
<select id="findAll" resultMap="userResultMap">
SELECT id id_,username username_,birthday birthday_,sex sex_,address address_ FROM USER
</select>
参数说明:
- resultMap标签:建立列与属性的映射关系。
- resultMap的id属性:需要与select中引用的resultMap名称一致。
- type:设置要封装对象的类型。
- id标签:数据库表主键字段的映射。
- column:代表数据库表字段名称。
- property:对象类型里面的属性值。
parameterType输入参数
java简单类型
- 简单类型包括:基本类型,String类型,包装类型。
注意事项:
参数类型不区分大小写,且能写多种形式。
- 例parameterType = "int",可以写成:
- _int
- integer
- Integer
- java.lang.Integer
注意:
- 不可以写成:int_
pojo包装类型
概述:
- 一个对象里面又包含了另外一个对象。
步骤:
- 新建一个对象:QueryVo,封装所有的查询条件。
- 接口方法中根据QueryVo作为输入参数查询。
示例:
<select id="findByCondition" parameterType="com.itheima.entity.QueryVo" resultType="com.itheima.entity.User">
select * from user where username=#{user.username}
and birthday>=#{start} and birthday <= #{end}
</select>
对数据库的增删改
添加操作
参数的说明:
- insert:执行的是插入操作。
- id:接口中的方法名字。
- resultType:设置返回类型,若没有设置,默认返回影响的行数。
- parameterType:设置接口方法参数类型。
保存获取主键值:(有两种方式)
方式一:获取主键最后的自增长值封装到对象中(推荐,可以根据不同数据库类型设置,既可以oracle,也可以mysql)
示例配置:
<insert id="save" parameterType="com.itheima.entity.User">
<selectKey resultType="int" keyColumn="id" keyProperty="id" order="AFTER">
SELECT LAST_INSERT_ID();
</selectKey>
insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
</insert>
参数说明:
- selectKey:获取主键最后的自增长值封装到对象中。
- resultType:主键类型,一般都是int
- keyColumn:主键在数据库表中的字段名
- keyProperty:主键在对象中的属性名。
- order:
- after:自增长主键插入数据之后获取主键值,适合支持具有自增长字段数据库,适合mysql。
- before:自增长主键插入数据之前获取主键值,适合oracle。因为oracle没有自增长列,是通过序列解决的。
方式二:获取自增长主键值。(不推荐,因为只适用于mysql,不适用于oracle)
- 设置标签属性:useGeneratedKeys = "true"
- 获取支持自增长字段数据库的主键值。
示例配置:
<insert id="save2" parameterType="com.itheima.entity.User" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
</insert>
修改操作
概述:
- update:代表修改操作。
删除操作:
概述:
delete:代表删除操作。
- 删除一般参数只有一个基本数据类型。parameterType="int"
- 此时在sql语句中,#{对象的属性名}里面的属性名,随便写。
单表查询
模糊查询
方式一:用ognl表达式(推荐,能防止sql注入)
格式:
- like #{属性名}
概述:
- #{}可以接收简单类型值或pojo属性值。
- #{}表示一个占位符号,通过#{}可以实现PrepareStatement向占位符中设置值,自动进行java类型和jdbc类型转换。
方式二:通过拼接字符串的方式实现(不推荐,因为在sql语句中拼接字符串方式实现的模糊查询,不能防止sql注入)
格式:
- like '[%]${value}[%]'
概述:
- ${}表示拼接sql串,通过$可以将parameterType传入的内容拼接在sql中且不进行jdbc类型转换。
- ${}可以接受简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。
- 如果传入的是pojo属性值,${}括号可以不用value,${对象中的属性值}。
特殊字符
概述:
- 需要使用转义方式。
- 大于号不需要转义,小于号需要转义。
转义有两种方式:
- 一个一个转义。
- 将一个区域里面的所有字符批量转义。
- 格式:<!CDATA[数据]>
示例代码:
<select id="findByCondition" resultType="com.itheima.entity.User" parameterType="com.itheima.entity.QueryVO">
<![CDATA[
select * from user where username like #{user.username} and birthday>=#{start} and birthday<=#{end}
]]>
</select>
SqlMapperconfig.xml配置文件详解
顺序 | 配置标签名称 | 说明 |
1 | properties | 属性 |
2 | settings | 配置全局参数 |
3 | typeAliases | 类型别名 |
4 | typeHandlers | 类型处理器 |
5 | objectFactory | 对象工厂 |
6 | plugins | 插件 |
7 | environments | 环境集合属性对象 |
8 | databaseIdProvider | 多数据库支持 |
9 | mappers | 映射器 |
- 在sqlMapconfig.xml中必须是从上往下的配置顺序。
Properties标签
属性:
- resource:引用本项目类路径下的properties文件数据。(外部)
- url:引用本项目外部properties文件数据,可以访问网络上的子标签。
子标签:
property:配置内部properties数据。(内部)
- 外部和内部可以一起使用,优先使用外部。
作用:
- 后面的environments标签的子标签dataSource用properties的数据。
示例配置:
<properties resource="jdbc.properties" >
<!--数据库连接字符串-->
<property name="jdbc.url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf8"></property>
<!--username数据库用户名-->
<property name="jdbc.username" value="root"></property>
<!--password数据库密码-->
<property name="jdbc.password" value="root"></property>
</properties>
<environments default="mysql">
<!--配置具体连接到哪一个数据库-->
<environment id="mysql">
<!--transactionManager,配置事物控制类型为JDBC-->
<transactionManager type="JDBC"></transactionManager>
<!--配置数据库连接池
POOLED,mybatis内置的数据库连接池(推荐使用)
UNPOOLED,不使用连接池
JNDI,使用服务器tomcat容器的数据库连接池
-->
<dataSource type="POOLED">
<!--mysql驱动类-->
<property name="driver" value="${jdbc.driver}"></property>
<!--数据库连接字符串-->
<property name="url" value="${jdbc.url}"></property>
<!--username数据库用户名-->
<property name="username" value="${jdbc.username}"></property>
<!--password数据库密码-->
<property name="password" value="${jdbc.password}"></property>
</dataSource>
</environment>
</environments>
typeAliases标签
作用:
- 用于起别名。
方式一:(不推荐)
参数说明:
- typeAlias:起别名配置,给一个一个类起别名。
- type:设置指定类型全名。
- alias:别名,在映射配置文件中类型只需要使用这个类名,不区分大小写。
示例:
<typeAliases>
<typeAlias type="com.itheima.entity.User" alias="user"></typeAlias>
</typeAliases>
方式二:(推荐)
参数说明:
- package:批量给指定名下所有类起别名,会自动将名下类名作为别名,不区分大小写。
示例:
<typeAliases>
<package name="com.itheima.entity"></package>
</typeAliases>
Mapper标签
方式一:一个一个映射文件加载。(不推荐)
<mappers>
<mapper resource="com/itheima/dao/IUserDao.xml"></mapper>
</mappers>
方式二:将这个包包下所有映射文件自动加载,批量加载。(推荐使用)
<mappers>
<package name="com.itheima.dao"></package>
</mappers>
Mybatis连接池与事务深入
Mybatis在初始化时,解析sqlMapperConfig.xml文件时,根据<dataSource>的type属性来创建相应类型的数据源DataSource:
1)type="pooled"
- 使用mybatis内置的数据库连接池。(推荐使用)
- Mybatis会创建PooledDataSource实例。
2)type="unpooled"
- 不使用连接池。
- Mybatis会创建unpooledDataSource实例。
2)type="judi"
- 使用服务器tomcat容器的数据库连接池。
- Mybatis会从jdni服务上查找DataSource实例,然后返回使用。
注意事项:
- PooledDataSource只是提供一种缓存连接池机制。
- Mybatis的PooledDataSource创建连接的时候,会自动调用UnpooledDataSource中创建连接的方法。
什么时候创建连接:
- 在真正进行数据库操作的时候,再创建连接。
Mybatis映射文件的SQL深入
<if>标签
作用:
- 用于条件判断的结构。
属性:
- test:条件判断,条件成立运行标签体的内容。
- 注意:条件里面的属性名必须为输入参数的类型属性。
示例:
<select id="findByCondition" parameterType="user" resultType="user">
select * from user where 1=1
<!-- 判断 -->
<if test="id != 0">
and id=#{id}
</if>
<if test="username != null">
and username=#{username}
</if>
</select>
<where>标签
作用:
- 用来优化<if>标签。
- <if>标签在<where>标签中嵌套使用,<where>标签能判断第一个成立的<if>标签,并去掉其sql语句的 and
- 通过<where>标签拼接where条件,简化where写法。
示例:
<select id="findByCondition" parameterType="user" resultType="user">
select * from user
<where>
<!-- 判断 -->
<if test="id != 0">
and id=#{id}
</if>
<if test="username != null">
and username=#{username}
</if>
</where>
</select>
<foreach>标签
作用:
- 遍历参数值。
参数说明:
- foreach:用于循环遍历。
- collection:用于遍历的集合,必须是输入类型的属性。
- open:拼接sql的开始部分。
- close:拼接sql的结束部分。
- separator:循环拼接的分割符号。
- index:当前遍历元素的索引。
- item:要遍历的元素(集合里面的每个元素的名字)
- #{id}:占位符的值,里面id名字与item设置的名字保持一致。
示例:
<select id="findByCondition2" parameterType="queryvo" resultType="user">
SELECT * FROM USER WHERE 1=1
<if test="ids != null and ids.size()>0">
<foreach collection="ids" open="and id IN (" separator="," close=")" item="id">
#{id}
</foreach>
</if>
</select>
<sql>标签
作用:
- 定义SQL片段,抽取公用的SQL部分。
<include>标签
作用:
- 用来引用sql片段。
总结:
- sql中可将重复的sql提取出来,使用时用include引用即可,最终达到sql重用的目的。
- <include>标签的refid属性的值就是<sql>标签定义的id的取值。
- 如果应用其他mapper.xml的sql片段,则在引用时需要加上namespace。
- 格式:<include refid = "空间名称.id的值"></include>
示例代码:
<sql id="selectUser">
SELECT * FROM USER WHERE 1=1
</sql>
<select id="findByCondition2" parameterType="queryvo" resultType="user">
<!--引用SQL片段-->
<include refid="selectUser"></include>
<if test="ids != null and ids.size()>0">
<foreach collection="ids" open="and id IN (" separator="," close=")" item="id">
#{id}
</foreach>
</if>
</select>
Mybatis的多表关联查询
常见的表关系:
- 一对一
- 一对多
- 多对多
- 双向一对多就是多对多。
一对一
参数说明:
- association标签:用于配置一对一映射。
- property属性:user对象在Accound对象中的属性名。
- javaType属性:user属性的java对象类型。(没有ofType属性)
- column属性:外键。
- id标签:数据库表主键字段映射。
示例代码:
<resultMap id="userResultMap" type="account">
<!--建立account账户对象属性与账户表字段的映射关系-->
<id property="accountId" column="accountId"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<association property="user" javaType="user" column="uid">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="birthday" column="birthday"></result>
<result property="sex" column="sex"></result>
<result property="address" column="address"></result>
</association>
</resultMap>
<select id="findAll" resultMap="userResultMap">
SELECT * FROM account a INNER JOIN USER u ON a.uid=u.id
</select>
一对多
参数说明:
- collection:用于配置一对多映射。
- property:在User里面的List<Account>的属性名。
- column:主键。
- ofType:当前account表的java类型。
- javaType:无意义,但也有这个属性。
示例:
<!--建立user对象的属性与查询列的映射关系-->
<resultMap id="userResultMap" type="user">
<!--1. 封装User对象-->
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="birthday" column="birthday"></result>
<result property="sex" column="sex"></result>
<result property="address" column="address"></result>
<collection property="accounts" ofType="account">
<id property="accountId" column="accountId"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
</collection>
</resultMap>
<!--使用左外连接,因为我们查询的是用户,用户下有账户才显示账户;用户下没有账户只显示用户-->
<select id="findAll" resultMap="userResultMap">
SELECT * FROM USER u LEFT JOIN account a ON a.uid=u.id
</select>
多对多
概述:
- 双向一对多就是多对多。
- 多对多的时候,collection不用设立主键,没有意义。
- 多对多时,需要设立中间表,中间表分别设立两个表主键的外键,并且把外键列设置为联合主键。
中间表创建语句示例:
CREATE TABLE user_role (
UID int(11) NOT NULL COMMENT '用户编号',
RID int(11) NOT NULL COMMENT '角色编号',
PRIMARY KEY (UID,RID),
KEY FK_Reference_10 (RID),
CONSTRAINT FK_Reference_10 FOREIGN KEY (RID) REFERENCES role (ID),
CONSTRAINT FK_Reference_9 FOREIGN KEY (UID) REFERENCES user (id)
)
示例代码:
<resultMap id="userResultMap" type="user">
<!--1.封装用户信息-->
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="birthday" column="birthday"></result>
<result property="sex" column="sex"></result>
<result property="address" column="address"></result>
<!--2. 封装用户的角色集合-->
<!--一对多配置-->
<collection property="roles" ofType="role">
<id property="id" column="roleId"></id>
<result property="roleName" column="role_name"></result>
<result property="roleDesc" column="role_desc"></result>
</collection>
</resultMap>
<!--注意:多表查询时候,列名称不要重复,否则影响结果封装!!!-->
<select id="findAll" resultMap="userResultMap">
SELECT u.*,r.ID roleId,r.ROLE_NAME,r.ROLE_DESC FROM USER u
LEFT JOIN user_role ur ON u.id=ur.UID
LEFT JOIN role r ON ur.RID=r.ID
</select>
用map做参数
概述:
- 使用map去替换QueryVo,用map做输入参数,此时标签中不用写parameter属性。
对象封装数据和使用map集合封装数据各自的优势:
- 对象更具有面向对象和提高重用性,map简单不用创建新的类型适合一次使用。
示例:
总结
- 当进行及时加载时(一次加载所有数据),可以都不写column。
- 其实所有操作标签都可以不写parameterType属性,但是为了方便操作,最好写上。虽然可以不写,但是写错的话会报错,写的话一定要写对。
Mybatis延迟加载策略
什么是及时加载:
- 一次加载所有数据。
延迟加载(懒加载):
- 需要用到数据时才进行加载,不需要用数据时就不加载数据。
好处:
- 先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度更快。
坏处:
- 因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时间,所以可能造成用户等待时间变长,造成用户体验下降。
如何实现延迟加载:
- association、collection具备延迟加载功能。通过设置select属性实现。
配置延迟加载
参数说明:
1)select:接口类全名.方法名
- 用于设置当用到用户数据的时候执行哪个接口的方法名字。
2)column:默认会将column指定的数据传递给select方法作为参数。
- 一对一时,column设外键。
- 一对多时,column设主键。
- 在延迟加载中,多对多也要设column。
示例:
IAccountDao接口:
public interface IAccountDao {
/**
* 查询全部
*/
List<Account> findAll();
}
IUserDao接口:
public interface IUserDao {
/**
* 根据用户id查询
*/
User findById(int id);
}
IUserDao.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 对应dao接口的路径-->
<mapper namespace="com.itheima.dao.IUserDao">
<!--parameterType 方法参数类型;resultType 表示返回值类型 -->
<select id="findById" parameterType="int" resultType="user">
SELECT * FROM USER WHERE id=#{id}
</select>
</mapper>
IAccountDao.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 对应dao接口的路径-->
<mapper namespace="com.itheima.dao.IAccountDao">
<!--一对一: 延迟加载查询(2) 结果集封装、以及延迟加载配置-->
<resultMap id="accountResultMap" type="account">
<id property="accountId" column="accountId"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<!--
延迟加载 配置:
select 延迟加载查询配置。
根据账户中用户的id,查询用户信息。
所以需要找到查询方法:com.itheima.dao.IUserDao.findById
-->
<association
property="user" javaType="user" column="uid"
select="com.itheima.dao.IUserDao.findById"></association>
</resultMap>
<!--一对一: 延迟加载查询(1)-->
<select id="findAll" resultMap="accountResultMap">
SELECT * FROM account;
</select>
</mapper>
注意事项:
- 需要手动开启延迟加载支持。默认不开启。
开启延迟加载
方式一:配置延迟加载的全局开关。
在SqlMapconfig.xml文件中:
<settings>
<!--配置延迟加载全局开关-->
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
- value默认为:false
方式二:设置fetchType属性
在Mapper.xml文件中:
- 通过在association或collection标签中配置fetchType属性为lazy开启延迟加载。
实例:
<association
property="user" javaType="user" column="uid"
select="com.itheima.dao.IUserDao.findById" fetchType="lazy"></association>
- fetchType="lazy"覆盖全局的配置。
Mybatis缓存
mybatis缓存分为:
- 一级缓存
- 二级缓存
一级缓存:
- 一级缓存是基于sqlSession缓存,关闭sqlSession,缓存就失效。
- 一级缓存不能跨sqlSession,由mybatis自动维护。
二级缓存:
- 二级缓存是基于映射文件的缓存。
- 不同的sqlSession可以访问二级缓存的内容。
- 二级缓存是跨sqlSession的。
- 二级缓存不能跨映射文件。
Redis和Mybatis缓存的区别:
- Redis缓存可以集群缓存,redis的缓存有持久化。
- Mybatis只适合单机缓存,mybatis的缓存没有持久化。
开启二级缓存的步骤:
第一步:开启二级缓存支持(可选)
- 二级缓存的全局配置,默认开启,所以这里可以配置,也可以不配置。
<settings>
<!--配置二级缓存的全局开关,默认为true(可选)-->
<setting name="cacheEnabled" value="true"></setting>
</settings>
第二步:配置映射文件
- 那些映射文件中的SQL查询的结果需要放入二级缓存,需要在映射文件中配置<cache/>
- 执行哪些方法时不需要使用二级缓存,要在映射文件中配置useCache="false"
在Mapper.xml文件中:
<select id="findById" resultType="user" useCache="true">
SELECT * FROM USER WHERE id=#{userid}
</select>
- userCache属性默认值为true
第三步:实体类实现可序列化接口
- Serializable
Mybatis注解开发
注意事项:
- 注解了的方法,不能再用xml文件去配置。
- 没与Spring整合前,使用注解也要配置SqlMapConfig.xml文件。并配置<mappers>标签的<package>标签,并创建对应的包。
注解说明:
@Insert | 实现新增 |
@Update | 实现更新 |
@Delete | 实现删除 |
@select | 实现查询 |
@Result | 实现结果集封装 |
@Results | 可以与@Result一起使用,封装多个结果集 |
@One | 实现一对一结果集封装 |
@Many | 实现一对多结果集封装 |
@Param | 当方法参数有多个的时候,建立sql语句中的占位符参数值与方法参数的映射关系 |
@Insert
@Update
@Delete
@Select
示例:
@Update("update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}")
void update(User user);
@Param
作用:
- 当方法参数有多个的时候。
- 例:分页sql的执行。
方式一:使用参数顺序方式
@Select("select * from user limit #{arg0},#{arg1}")
List<User> findByPage2(int start,int count);
方式二:使用@Param注解,定义到方法参数上,与sql语句中的占位符中的名称对应。
@Select("select * from user limit #{start},#{count1}")
List<User> findByPage3(@Param("start") int start, @Param("count1") int count);
用注解延迟加载封装数据
- 必须指定id列的映射,否则为null。
一对一映射,以及延迟加载配置
IUserDao接口:
public interface IUserDao {
/**
* 根据用户id查询用户
*/
@Select("select * from user where id=#{uid}")
User findById(int uid);
}
IAccountDao接口:
public interface IAccountDao {
@Select("select * from account")
@Results({
@Result(id = true,property = "accountId",column = "accountId"),
@Result(property = "uid",column = "uid"),
@Result(property = "money",column = "money"),
// 一对一
@Result(property = "user",column = "uid",javaType = User.class,
one = @One(select = "com.itheima.dao.IUserDao.findById",fetchType = FetchType.LAZY))
})
List<Account> findAll();
}
参数说明:
- @Results:建立多个查询列与对象属性的映射关系。
- @Result:建立每一个查询列与对象属性的映射关系。
- @id:标记主键字段,默认为false。
- property:对象属性。
- column:对象属性对应的查询列。
- one:此属性表示一对一关系。
@One:one属性的值的类型,就是一个注解类型,表示一对一。
- select:延迟加载查询。对应用户接口中,根据用户id查询用户的方法。
- fetchType:是否开启延迟加载支持。
一对多映射,以及延迟加载配置
IUserDao接口:
public interface IUserDao {
@Select("select * from user")
@Results({
@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",javaType = List.class,
many = @Many(select = "com.itheima.dao.IAccountDao.findAccountsByUserId",
fetchType = FetchType.LAZY))
})
List<User> findAll();
}
IAccountDao接口:
public interface IAccountDao {
@Select("select * from account where uid=#{uid}")
List<Account> findAccountsByUserId(int uid);
}
参数说明:
javaType=List.class:集合的类型
many:表示一对多关系
- fetchType:是否开启延迟加载策略。
- select:一对多延迟加载查询。
一对一映射,不使用select属性
Product类属性:
public class Product {
private Long id;//id
private String productNum;//产品编号
private String productName;//产品名称
private String cityName;//出发城市
private Timestamp departureTime;//出发时间
private double productPrice;//产品价格
private String productDesc;//产品描述
// 0 关闭; 1 开启
private Integer productStatus;//产品状态
}
order类属性:
public class Order {
private Long id;
private String orderNum;
private Date orderTime;
private Integer peopleCount;
private String orderDesc;
private Integer payType;
private Integer orderStatus;
// 订单对应的产品
private Product product;
}
IOrderDao:
public interface IOrderDao {
/**
* 查询全部
*/
@Select("select o.id oid,o.ordernum,o.ordertime,o.peoplecount,o.orderdesc,o.paytype,o.orderstatus\n" +
",p.* from orders o inner join product p on o.productid=p.id")
@Results({
// 订单信息,只要指定id列与属性的映射关系,其他列会自动封装(属性与列一致)
@Result(property = "id", column = "oid"),
// 产品信息
@Result(property = "product.id", column = "id"),
@Result(property = "product.productNum", column = "productNum"),
@Result(property = "product.productName", column = "productName"),
@Result(property = "product.cityName", column = "cityName"),
@Result(property = "product.departureTime", column = "departureTime"),
@Result(property = "product.productPrice", column = "productPrice"),
@Result(property = "product.productDesc", column = "productDesc"),
@Result(property = "product.productStatus", column = "productStatus"),
})
List<Order> findAll();
}
注意事项:
- 注意数据库字段名重复的问题,在数据库的查询中·,重复的字段应该取别名,避免重复。
- Order类的映射关系,可写可不写,会自动封装。
对用注解实现映射的总结
注意事项:
- 无论时一对一还是一对多,在注解中,都使用javaType
- 在一对一时,xml配置形式的javaType,设为:实体类.class
- 在一对多时,xml配置形式的ofType,设为:List.class
- 在注解中,javaType可以忽略不写。
用注解实现二级缓存
在接口上使用注释@CacheNamespace,将这个接口加入二级缓存。
给接口的方法添加@Options,设置接口中当前的方法不加入二级缓存。