一:搭建MyBatis框架的注意事项
1:开发环境
1.1.驱动类driver-class-name
MySQL 5版本使用dbc5驱动,驱动类使用:com.mysql.jdbc.Driver
MySQL 8版本使用dbc8驱动,驱动类使用:com.mysql.cj.jdbc.Driver
1.2.连接地址url
MySQL 5版本的url:
jdbc:mysql://localhost:3306/ssm
MySQL 8版本的url:
jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC
8.0.25之后可以省略时区的设置
2.创建maven工程
需要在pom.xml文件中设置打包方式为jar
3:创建MyBatis的映射文件
相关概念:ORM(Object Relationship Mapping)对象关系映射
·对象:Java的实体类对象
·关系:关系型数据库
·映射:二者之间的对应关系
Java概念 |
数据库概念 |
类 |
表 |
属性 |
字段/列 |
对象 |
记录/行 |
3.1.映射文件命名规则:
表所对应的实体类的类名+Mapper.xml
例如:表tb_user,映射的实体类为User,所对应的映射文件为UserMapper.xml
因此一个映射文件对应一个实体类,对应一张表中的操作
MyBatis映射文件用于编写SQL,访问以及操作表中的数据
MyBatis映射文件存放的位置是src/main/resources/mappers目录下
3.2.MyBatis中可以面向接口操作数据,要保证两个一致:
①mapper接口的全类名和映射文件的命名空间(namespace)保持一致(也就是说mapper接口的名称要和映射文件的名称一样)
②mapper接口中方法的方法名和映射文件中编写SQL的标签的id属性保持一致
4:在测试中使用MyBatis中相应的优化
4.1.mapper中的方法调用除了使用 mapper.方法名 的方式还可以使用 sqlSession.操作类型("namespace.sqlid") 的方式来调用
如sqlSession.insert("com.zsw.mybatis.mapper.UserMapper.insertUser");
4.2.对于修改,添加,删除的SQL操作都需要进行sqlSession.commit;
的操作太过麻烦可以在创建sqlSession时设置自动提交,如:sqlSessionFactory.openSession(true);
二:设置log4j.xml日志
1.先在pom.xml文件中导入相应的jar包
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
2.在src/main/resources目录下存放log4j.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
<param name="Encoding" value="UTF-8"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS}
%m (%F:%L) \n"/>
</layout>
</appender>
<logger name="java.sql">
<level value="debug"/>
</logger>
<logger name="org.apache.ibatis">
<level value="info"/>
</logger>
<root>
<level value="debug"/>
<appender-ref ref="STDOUT"/>
</root>
</log4j:configuration>
3.日志的级别
FATAL(致命)>ERROR(错误)>WARN(警告)>INFO(信息)>DEBUG(调试)
从左到右打印越来越详细
三:MyBatis核心配置文件详解
注意:对应MyBatis中各个部分配置的顺序
properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?
1:enviroments
enviroments:配置连接数据库的环境
default:设置默认使用的环境的id
1.1.environment
environment:设置一个具体的连接数据库的环境
id:设置环境的唯一标识,不能重复
1.2.transactionManager
transactionManager:设置事务管理器属性
type:设置事务管理的方式
type="JDBC | MANAGED"
JDBC:表示使用JDBC中原生的事务管理方式
MANAGED:被管理,例如Spring
1.3.dataSource
dataSource:设置数据源
type:设置数据源类型
type="POOLED | UNPOOLED | JNDI"
POOLED:表示使用数据库连接池
UNPOOLED:表示不使用数据库连接池
JNDI:表示使用上下文中的数据库源
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
</dataSource>
</environment>
</environments>
2:properties
可以创建一个jdbc.properties文件在其中设置
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm
jdbc.username=root
jdbc.password=123456
然后在mybatis-config.xml文件中来引用properties文件:<properties resource="jdbc.properties" />
以后就可以使用${key}的方式来访问value
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
3:typeAliases
typeAliases:设置类型别名,即为某个具体类型设置一个别名
在MyBatis的范围中,就可以使用别名表示一个具体的类型
3.1.type:设置需要起别名的类型
alias:设置某个类型的别名(如果不设置alias,当前的类型拥有默认的别名,即类名且不区分大小写)
<typeAlias type="com.zsw.mybatis.pojo.User" alias="User"/>
3.2.通过包设置类型别名,指定包下所有的类型将全部拥有默认的别名,即类名且不区分大小写
<package name="com.zsw.mybatis.pojo"/>
4:mappers
引入MyBatis的映射文件
4.1.使用resource的方式来引入映射文件,resource是映射文件所在的位置
<mapper resource="mappers/UserMapper.xml"/>
4.2.可以以包的方式引入映射文件,但是必须满足两个条件:
①mapper接口和映射文件所在的包必须一致
②mapper接口的名字和映射文件的名字必须一致
<package name="com.zsw.mybatis.mapper"/>
四:MyBatis获取参数值的两种方式
1:MyBatis获取参数值的两种方式:${}和#{}
1.${}的本质就是字符串拼接,#{}的本质就是占位符赋值
2.${}使用字符串拼接的方式拼接sql,若为字符串类型或日期类型的字段进行赋值时,需要手动加单引号;但是#{}使用占位符赋值的方式拼接sql,此时为字符串类型或日期类型的字段进行赋值时,可以自动添加单引号
2:单个字母量类型的参数
1.若mapper接口中的方法参数为单个的字面量类型
2.此时可以使用${}和#{}以任意的名称获取参数的值,一定要注意${}需要手动加单引号
select * from tb_user where username = #{username}
select * from tb_user where username = '${username}'
3:多个字面量类型的参数
若mapper接口中的方法参数为多个时,此时MyBatis会自动将这些参数放在一个map集合中,以arg0,arg1...为键,以参数为值;以param1,param2...为键,以参数为值;
因此只需要通过${}和#{}访问map集合的键就可以获取相对应的值,一定要注意${}需要手动加单引号
<!-- User Login(String name,String password);-->
<select id="Login" resultType="User">
select * from tb_user where username = #{arg0} and password = #{arg1}
</select>
4:map集合类型的参数
若mapper接口中的方法需要的参数类型为多个时,此时可以手动创建map集合,将这些数据放在map中
只需要通过${}和#{}访问map集合的键,就可以获取相对应的值,一定要注意${}需要手动加单引号
<!--User LoginByMap(Map map);-->
<select id="LoginByMap" resultType="user">
select * from tb_user where username = #{username} and password = #{password}
</select>
5:实体类类型的参数
若mapper接口方法的参数为实体类类型的参数,因为这相当于自动封装成了一个map集合
只需要通过#{}和${}访问实体类中的属性名,就可以获取相对应的属性值,一定要注意${}的单引号问题
<!-- User LoginByUser(User user);-->
<select id="LoginByUser" resultType="user">
select * from tb_user where username = #{username} and password = #{password}
</select>
6:使用@param标识参数
可以在mapper接口方法的参数上设置@param注解
此时MyBatis会将这些参数放在map中,以两种方式进行存储
①以@param注解的value属性值为键,以参数为值
②以param1,param2...为键,以参数为值
只需要通过${}和#{}访问map集合的键,就可以获取相对应的值,一定要注意${}需要手动加单引号
<!-- User LoginByParam(@Param("username")String username,@Param("password")String password);-->
<select id="LoginByParam" resultType="user">
select * from tb_user where username = #{username} and password = #{password}
</select>
五:MyBatis的查询、删除与添加
1:查询
1.查询一个实体类对象
mapper:User selectById(Integer id);
xml:
<!-- User selectById();-->
<select id="selectById" resultType="User">
select * from tb_user where id = #{id}
</select>
2.查询一个list集合
mapper:List<User> SelectAll();
xml:
<!-- List<User> SelectAll();-->
<select id="SelectAll" resultType="user">
select * from tb_user
</select>
注意:
①若SQL语句查询的结果为多条时,一定不能以实体类类型作为方法返回值,否则会抛出异常TooManyResultsException
②若SQL语句查询的结果为一条时,此时可以使用实体类类型或list集合类型作为方法的返回值
3.查询返回值为Java中基础类型
如:mapper:int totalData();
xml:
<!-- int totalData();-->
<select id="totalData" resultType="integer">
select count(*) from tb_user
</select>
MyBatis中为Java中常用的类型设置了类型别名:
Integer:Integer,int
int:_int,_integer
Map:map
String:string ......
4.查询返回值为Map集合
mapper:Map<String,Object> selectData(@Param("id")Integer id);
xml:
<!-- Map<String,Object> selectData(@Param("id")Integer id);-->
<select id="selectData" resultType="map">
select * from tb_user where id = #{id}
</select>
5.查询所有的用户信息为Map集合
若查询的数据有多条时,并且要将每条数据转换为Map集合
此时有两种解决方案:
①将mapper接口方法的返回值设置为泛型是Map的list集合
mapper:List<Map<String,Object>> selectAllData();
xml:
<!-- List<Map<String,Object>> selectAllData();-->
<select id="selectAllData" resultType="map">
select * from tb_user
</select>
②可以将每条数据转换的Map集合放在一个大的Map中,但是必须要通过@MapKey注解将查询的某个字段的值作为大的Map的键
mapper:
@MapKey("id")
Map<String,Object> selectByMap();
xml:
<!-- Map<String,Object> selectByMap();-->
<select id="selectByMap" resultType="map">
select * from tb_user
</select>
6.模糊查询
mapper:List<User> selectByUsername(@Param("username")String username);
模糊查询的映射文件有三种写法方式:
select * from tb_user where username like '%${username}%'
select * from tb_user where username like concat('%',#{username},'%')
select * from tb_user where username like "%"#{username}"%"
7.动态设置表名
mapper:List<User> setTableName(@Param("tableName")String tableName);
xml:
<!-- List<User> setTableName(@Param("tableName")String tableName);-->
<select id="setTableName" resultType="USER">
select * from ${tableName}
</select>
2:删除
mapper:void deleteByIds(@Param("ids")String ids);
xml:
<!-- void deleteByIds(@Param("ids")String ids);-->
<delete id="deleteByIds">
delete from tb_user where id in (${ids})
</delete>
注意:因为使用#{}会自动添加单引号,但是在()中的数据不能加单引号,因此只能使用${}来匹配数据
3:添加(获取自增的主键)
useGeneratedKeys:设置使用自增的主键
KeyProperty:因为增删改有统一的返回值是受影响的行数,因此只能将获取的自增的主键放在传输的参数实体类对象的某个属性中
mapper:void insertUser(User user);
xml:
<!-- void insertUser(User user);-->
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
insert into tb_user values (null,#{username},#{password},#{age},#{gender},#{email})
</insert>
六:处理字段名和属性名不一致的情况
1:设置别名处理
为查询的字段设置别名,和属性名保持一致
xml:
<!-- Emp selectById(@Param("empId")Integer empId);-->
<select id="selectById" resultType="emp">
select emp_id empId,emp_name empName,age,gender from tb_emp where emp_id = #{empId}
</select>
2:使用全局配置处理
当字段符合MySQL的要求使用_,而属性符合Java的要求使用驼峰
此时可以在MyBatis的核心配置文件中设置一个全局配置,可以自动将下划线映射为驼峰
如:emp_id --> empId;emp_name --> empName
mybatis-config:
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
xml:
<!-- Emp selectById(@Param("empId")Integer empId);-->
<select id="selectById" resultType="emp">
select * from tb_emp where emp_id = #{empId}
</select>
3:使用ResultMap处理
resultMap:设置自定义的映射关系
id:唯一标识
type:处理映射关系的实体类的类型
常用的标签:
id:处理主键和实体类中实现的映射关系
result:处理普通字段和实体类中属性的映射关系
column:处理普通映射关系中的字段名,必须是sql查询出的某个字段
property:设置映射关系中的属性的属性名,必须是处理的实体类类型中的属性名
xml:
<resultMap id="empResultMap" type="emp">
<id column="emp_id" property="empId"></id>
<result column="emp_name" property="empName"></result>
<result column="age" property="age"></result>
<result column="gender" property="gender"></result>
</resultMap>
<!-- Emp selectById(@Param("empId")Integer empId);-->
<select id="selectById" resultMap="empResultMap">
select * from tb_emp where emp_id = #{empId}
</select>
七:处理多对一映射关系和一对多映射关系
1:处理多对一映射关系
1.使用级联的方式处理多对一映射关系
xml:
<resultMap id="empResultMap" type="emp">
<id column="emp_id" property="empId"></id>
<result column="emp_name" property="empName"></result>
<result column="age" property="age"></result>
<result column="gender" property="gender"></result>
<result column="dept_id" property="dept.deptId"></result>
<result column="dept_name" property="dept.deptName"></result>
</resultMap>
<!-- Emp selectEmpAndDeptById(@Param("empId")Integer empId);-->
<select id="selectEmpAndDeptById" resultMap="empResultMap">
select tb_emp.*,tb_dept.* from tb_emp left join tb_dept on tb_emp.dept_id = tb_dept.dept_id where tb_emp.emp_id = #{empId}
</select>
2.使用association处理多对一映射关系
association:处理多对一的映射关系(处理实体类类型的属性)
property:设置需要处理映射关系的属性的属性名
javaType:设置要处理的属性的类型
xml:
<resultMap id="empAndDeptResultMap" type="emp">
<id column="emp_id" property="empId"></id>
<result column="emp_name" property="empName"></result>
<result column="age" property="age"></result>
<result column="gender" property="gender"></result>
<association property="dept" javaType="dept">
<id column="dept_id" property="deptId"></id>
<result column="dept_name" property="deptName"></result>
</association>
</resultMap>
<!-- Emp selectEmpAndDeptById(@Param("empId")Integer empId);-->
<select id="selectEmpAndDeptById" resultMap="empAndDeptResultMap">
select tb_emp.*,tb_dept.* from tb_emp left join tb_dept on tb_emp.dept_id = tb_dept.dept_id where tb_emp.emp_id = #{empId}
</select>
3.使用分布查询处理
select:设置分布查询出的SQL的唯一标识
column:将查询出的某个字段作为分步查询的SQL条件
例如:
EmpMapper:
mapper:Emp selectEmpAndDeptStepOne(@Param("empId")Integer empId);
xml:
<resultMap id="empAndDeptStepResultMap" type="emp">
<id column="emp_id" property="empId"></id>
<result column="emp_name" property="empName"></result>
<result column="age" property="age"></result>
<result column="gender" property="gender"></result>
<association property="dept" select="com.zsw.mybatis.mapper.DeptMapper.selectEmpAndDeptStepTwo" column="dept_id"></association>
</resultMap>
<!-- Emp selectEmpAndDeptStep(@Param("empId")Integer empId);-->
<select id="selectEmpAndDeptStepOne" resultMap="empAndDeptStepResultMap">
select * from tb_emp where emp_id = #{empId}
</select>
DeptMapper:
mapper:Dept selectEmpAndDeptStepTwo(@Param("deptId") Integer deptId);
xml:
<!-- Dept selectEmpAndDeptStepTwo(@Param("deptId") Integer deptId);-->
<select id="selectEmpAndDeptStepTwo" resultType="dept">
select * from tb_dept where dept_id = #{deptId}
</select>
分布查询的优点:可以实现延迟加载
但是必须要在核心配置文件中设置全局配置信息:
lazyLoadingEnabled:延迟加载的全局开关。当开启时。所有关联对象都会延迟加载
aggressiveLazyLoading:当开启时,任何方法的调用都会加载该对象的所有属性。否则每个属性都会按需加载
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
此时就可以实现按需加载,获取的数据是什么,就只会执行相应的SQL。此时可通过association和collection中的fetchType属性设置当前的分步查询是否使用延迟加载,fetchType="lazy(延迟加载) | eager(立即加载)"
<association property="dept" fetchType="lazy(eager)" select="com.zsw.mybatis.mapper.DeptMapper.selectEmpAndDeptStepTwo" column="dept_id"></association>
2:处理一对多映射关系
1.使用collection处理
collection:处理一对多的映射关系(处理集合类型的属性)
oftype:设置集合类型的属性中存储的数据的类型
mapper:Dept selectDeptAndEmp(@Param("deptId") Integer deptId);
xml:
<!-- Dept selectDeptAndEmp(@Param("deptId") Integer deptId);-->
<resultMap id="selectDeptAndEmp" type="dept">
<id column="dept_id" property="deptId"></id>
<result column="dept_name" property="deptName"></result>
<collection property="emps" ofType="emp">
<id column="emp_id" property="empId"></id>
<result column="emp_name" property="empName"></result>
<result column="age" property="age"></result>
<result column="gender" property="gender"></result>
</collection>
</resultMap>
<select id="selectDeptAndEmp" resultMap="selectDeptAndEmp">
select * from tb_dept left join tb_emp on tb_dept.dept_id = tb_emp.dept_id where tb_dept.dept_id = #{deptId}
</select>
2.使用分步查询处理
DeptMapper:
mapper:Dept selectDeptAndEmpStepOne(@Param("deptId") Integer deptId);
xml:
<!-- Dept selectDeptAndEmpStepOne(@Param("deptId") Integer deptId);-->
<resultMap id="selectDeptAndEmpStepOne" type="dept">
<id column="dept_id" property="deptId"></id>
<result column="dept_name" property="deptName"></result>
<collection property="emps" select="com.zsw.mybatis.mapper.EmpMapper.selectDeptAndEmpStepTwo" column="dept_id"></collection>
</resultMap>
<select id="selectDeptAndEmpStepOne" resultMap="selectDeptAndEmpStepOne">
select * from tb_dept where dept_id = #{deptId}
</select>
EmpMapper:
mapper:List<Emp> selectDeptAndEmpStepTwo(@Param("deptId")Integer dept_id);
xml:
<!-- List<Emp> selectDeptAndEmpStepTwo(@Param("deptId")Integer dept_id);-->
<select id="selectDeptAndEmpStepTwo" resultType="emp">
select * from tb_emp where dept_id = #{deptId}
</select>
八:动态SQL和标签
1:动态SQL
MyBatis框架的动态SQL技术是一种根据特定条件动态拼接SQL语句的功能,它存在的意义是为了解决拼接SQL语句字符串时的痛点问题
2:标签
1.if标签
if,通过test属性中的表达式判断标签中的内容是否有效(是否会拼接到SQL中)
2.where标签
①若where标签中有条件成立,会自动生成where关键字
②会自动将where标签中内容前多余的and去掉,但是其中内容后多余的and无法去掉
③若where标签中没有任何一个条件成立,则where没有任何功能
xml:
<!-- Emp selectEmpByCondition(Emp emp);-->
<select id="selectEmpByCondition" resultType="emp">
select * from tb_emp
<where>
<if test="empName != null and empName != ''">
and emp_name = #{empName}
</if>
<if test="age != null">
and age = #{age}
</if>
<if test="gender != null and gender != ''">
and gender = #{gender}
</if>
</where>
</select>
3.trim标签
prefix、suffix:在标签中内容前面或后面添加指定内容
prefixOverrides、suffixOverrides:在标签中内容前面或后面去掉指定内容
xml:
<!-- List<Emp> selectEmpByConditionTrim(Emp emp);-->
<select id="selectEmpByConditionTrim" resultType="emp">
select * from tb_emp
<trim prefix="where" suffixOverrides="and">
<if test="empName != null and empName != ''">
emp_name = #{empName} and
</if>
<if test="age != null">
age = #{age} and
</if>
<if test="gender != null and gender != ''">
gender = #{gender}
</if>
</trim>
</select>
4.choose、when、otherwise标签
相当于Java中的if...else if...else
when至少设置一个,otherwise最多设置一个
xml:
<!-- List<Emp> selectEmpByChoose(Emp emp);-->
<select id="selectEmpByChoose" resultType="emp">
select * from tb_emp
<where>
<choose>
<when test="empName != null and empName != ''">
and emp_name = #{empName}
</when>
<when test="age != null">
and age = #{age}
</when>
<when test="gender != null and gender != ''">
and gender = #{gender}
</when>
</choose>
</where>
</select>
5.foreach标签
collection:设置要循环的数组或集合
item:用一个字符串表示数组或集合中的每一个数据
separator:设置每次循环的数据之间的分隔符
open:循环的所有内容以什么开始
close:循环的所有内容以什么结束
xml:
<!-- void InsertEmps(@Param("emps")List<Emp> emps);-->
<insert id="InsertEmps" useGeneratedKeys="true" keyProperty="empId">
insert into tb_emp values
<foreach collection="emps" item="emp" separator=",">
(null,#{emp.empName},#{emp.age},#{emp.gender},#{emp.deptId})
</foreach>
</insert>
<!-- void deleteEmps(@Param("empIds")Integer empIds);-->
<delete id="deleteEmps">
delete from tb_emp where emp_id in
<foreach collection="empIds" item="empId" separator="," open="(" close=")">
#{empId}
</foreach>
</delete>
<!-- void deleteEmps(@Param("empIds")Integer empIds);-->
<delete id="deleteEmps">
delete from tb_emp where emp_id in
<foreach collection="empIds" item="empId" separator="or">
emp_id = #{empId}
</foreach>
</delete>
6.sql标签
可以记录一段SQL,在需要用的地方使用include标签进行引用
记录:
<sql id="delete">
delete from tb_emp where
</sql>
使用:
<delete id="deleteEmps">
<include refid="delete"></include>
<foreach collection="empIds" item="empId" separator="or">
emp_id = #{empId}
</foreach>
</delete>
九:MyBatis缓存
1:一级缓存
1.一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中获取,不会从数据库重新访问
2.使一级缓存失效的四种情况:
①不同的SqlSession对应不同的一级缓存
②同一个SqlSession但是查询条件不同
③同一个SqlSession两次查询期间执行了任何一次增删改操作
④同一个SqlSession两次查询期间手动清空了缓存sqlSession.clearCache();
2:二级缓存
1.二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取
2.二级缓存开启的条件:
①在核心配置文件中。设置全局配置属性cacheEnabled="true",默认为true,不需要设置
②在映射文件中设置标签<cache/>
③二级缓存必须在SqlSession关闭或提交之后有效
④查询的数据所转换的实体类类型必须实现序列化的接口public class Emp implements Serializable
3.使二级缓存失效的情况:
两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效
4.二级缓存中的相关配置:
在mapper配置文件中添加的cache标签可以设置一些属性:
①eviction属性:缓存回收策略,默认是LRU
a>LRU (Least Recently Used) -最近最少使用的:移除最长时间不被使用的对象
b>FIFO (First In First out) -先进先出:按对象进入缓存的顺序来移除它们
c>SOFT -软引用:移除基于垃圾回收器状态和软引用规则的对象
d>WEAK -弱引用:更积极地移除基于垃圾回收器状态和弱引用规则的对象
②flushInterval属性:刷新间隔,单位毫秒
默认情况下是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新
③size属性:引用数目,正整数
代表缓存最多可以存储多少个对象,太大容易导致内存溢出
④readOnly属性:只读,true/false
true:只读缓存;会给所有调用者返回缓存对象的相同实例。因为这些对象不能被修改。这提供了很重要的性能优势
false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false。
3:MyBatis缓存查询的顺序
先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用。
如果二级缓存没有命中,再查询一级缓存
如果一级缓存也没有命中,则查询数据库
SqlSession关闭之后,一级缓存中的数据会写入二级缓存
4:整合第三方缓存EHCache
1.添加依赖
<!--MyBatis EHCache整合包-->
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.2.1</version>
</dependency>
<!--slf4j日志门面的一个具体实现-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
2.各jar包功能
jar包名称 |
作用 |
mybatis-ehcahe |
MyBatis和EHCache的整合包 |
ehcache |
EHCache核心包 |
slf4j-api |
SLF4j日志门面包 |
logback-classic |
支持SLF4j门面接口的一个具体实现 |
3.创建EHCache的配置文件ehcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
updateCheck="false">
<!--
diskStore:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置。参数解释如下:
user.home – 用户主目录
user.dir – 用户当前工作目录
java.io.tmpdir – 默认临时文件路径
-->
<diskStore path="java.io.tmpdir/Tmp_EhCache"/>
<!--
defaultCache:默认缓存策略,当ehcache找不到定义的缓存时,则使用这个缓存策略。只能定义一个。
-->
<!--
name:缓存名称。
maxElementsInMemory:缓存最大数目
maxElementsOnDisk:硬盘最大缓存个数。
eternal:对象是否永久有效,一但设置了,timeout将不起作用。
overflowToDisk:是否保存到磁盘,当系统当机时
timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
clearOnFlush:内存数量最大时是否清除。
memoryStoreEvictionPolicy:可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。
FIFO,first in first out,这个是大家最熟的,先进先出。
LFU, Less Frequently Used,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。
LRU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
-->
<defaultCache
eternal="false"
maxElementsInMemory="10000"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="259200"
memoryStoreEvictionPolicy="LRU"/>
<cache
name="cloud_user"
eternal="false"
maxElementsInMemory="5000"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="1800"
memoryStoreEvictionPolicy="LRU"/>
</ehcache>
4.设置二级缓存的类型<cache type="org.mybatis.caches.ehcache.EHcacheCache"/>
5.加入logback日志
存在log4j时,作为简易日志的log4j将失效,此时我们需要借助SLF4J的具体实现logback来打印日志。创建logback的配置文件logback.xml
十:MyBatis的逆向工程
正向工程:先创建Java实体类,由框架负责根据实体类生成数据库表。Hibernate是支持正向工程的
逆向工程:先创建数据库,由框架负责根据数据库表,反向生成如下资源:
①Java实体类
②Mapper接口
③Mapper映射文件
创建逆向工程的步骤
1.添加依赖和插件
<packaging>jar</packaging>
<!-- 依赖MyBatis核心包 -->
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<!-- junit测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!-- log4j日志 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.2.0</version>
</dependency>
</dependencies>
<!-- 控制Maven在构建过程中相关配置 -->
<build>
<!-- 构建过程中用到的插件 -->
<plugins>
<!-- 具体插件,逆向工程的操作是以构建过程中插件形式出现的 -->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.0</version>
<!-- 插件的依赖 -->
<dependencies>
<!-- 逆向工程的核心依赖 -->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.2</version>
</dependency>
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
2.添加配置文件
<?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>
<!--
targetRuntime: 执行生成的逆向工程的版本
MyBatis3Simple: 生成基本的CRUD(清新简洁版)
MyBatis3: 生成带条件的CRUD(奢华尊享版)
-->
<context id="DB2Tables" targetRuntime="MyBatis3">
<!-- 数据库的连接信息 -->
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/ssm?
serverTimezone=UTC"
userId="root"
password="123456">
</jdbcConnection>
<!-- javaBean的生成策略-->
<javaModelGenerator targetPackage="com.zsw.mybatis.pojo"
targetProject=".\src\main\java">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- SQL映射文件的生成策略 -->
<sqlMapGenerator targetPackage="com.zsw.mybatis.mapper"
targetProject=".\src\main\resources">
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<!-- Mapper接口的生成策略 -->
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.zsw.mybatis.mapper" targetProject=".\src\main\java">
<property name="enableSubPackages" value="true" />
</javaClientGenerator>
<!-- 逆向分析的表 -->
<!-- tableName设置为*号,可以对应所有表,此时不写domainObjectName -->
<!-- domainObjectName属性指定生成出来的实体类的类名 -->
<table tableName="tb_emp" domainObjectName="Emp"/>
<table tableName="tb_dept" domainObjectName="Dept"/>
</context>
</generatorConfiguration>
3.在Maven的插件中找到 "mybatis-generator" 并且运行它之后便会生成相应的文件
4.注意:
①对于清晰简洁版只会生成五种增删改查方法
②对于豪华尊享版它的修改方法有两种
一种是updateByExample
若使用它修改 给相对应的数据赋值为null时便只会将null赋值给它
另一种是updateByExampleSelective
若使用它修改 给相对应的数据赋值为null时 它并不会将数据的值设置为null 而是会将其修改为默认值 或者不修改就使用原本的值
十一:分页功能
1.添加依赖
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.2.0</version>
</dependency>
2.配置分页插件
在MyBatis的核心配置文件中配置插件
<plugins>
<!--设置分页插件-->
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
3.分页插件的使用
①在查询功能之前使用PageHelper.startPage(int pageNum,int pageSize)
开启分页功能
如:Page<Object> page = PageHelper.startPage(1, 4);
pageNum:当前页的页码
pageSize:每页显示的条数
②在查询获取list集合之后,使用pageInfo<T> pageInfo = new pageInfo<>(List<T> list,int navigatePages)
获取分页相关数据
如:PageInfo<Emp> pageInfo = new PageInfo<>(emps,5);
list:分页之后的数据
navigatePages:导航分页的页码数
4.相关属性介绍
pageNum:当前页的页码
pageSize:每页显示的条数
size:当前页显示的真实条数
total:总记录数
pages:总页数
prePage:上一页的页码
nextPage:下一页的页码
isFirstPage/isLastPage:是否为第一页/最后一页
hasPreviousPage/hasNextPage:是否存在上一页/下一页
navigatepageNums:导航分页的页码,[1,2,3,4,5.....]