MyBatis 框架
MyBatis 框架
- MyBatis 简介
- 搭建 MyBatis 开发环境
- 核心配置文件详解
- mapper 映射文件(实现增删改查)
- MyBatis获取参数值的两种方式
- MyBatis的各种查询功能
- 特殊SQL的执行
- 自定义映射resultMap
- resultMap 字段和属性的映射
- 多对一映射处理
- 一对多映射处理
- 动态SQL
- MyBatis的缓存
- MyBatis的逆向工程
- 分页插件
MyBatis 简介
MyBatis 是一个基于Java 的持久层框架。
- MyBatis 支持定制化SQL,存储过程以及高级映射,是一个非常优秀的持久层框架。
- MyBatis 对JDBC的设置参数和获取结果集的操作进行封装。
- MyBatis 可以使用xml或注解用于配置和原始映射,将接口和Java的POJO映射成数据库中的记录。
- MyBatis 是一个半自动的ORM框架(SQL语句要自己写)
和其它持久化层技术对比
- JDBC。SQL 夹杂在Java代码中,耦合度高,维护困难,实际开发中SQL有变化,频繁修改的情况多见,代码冗长,开发效率低。
- Hibernate 和 JPA。操作简单,开发效率高,程序中的长难复杂 SQL 需要绕过框架。内部自动生产的SQL,不容易做特殊优化。基于全映射的全自动框架,大量字段的POJO进行部分映射时比较困难。反射操作太多,导致数据库性能下降。
- MyBatis。轻量级,性能出色,SQL和Java代码分开,功能边界清晰。Java代码专注业务,SQL语句专注数据。SQL 语句定制化高。
搭建 MyBatis 开发环境
在项目中使用 MyBatis 框架,需要在pom中引入依赖。
<dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>x.x.x</version>
</dependency>
需要配置MyBatis 的核心配置文件。通过配置文件来获取 SqlSessionFactory 对象,SqlSessionFactory 用来创建SQL 的会话,通过SQL 会话进一步操作数据库。
SqlSession:代表Java程序和数据库之间的会话。
SqlSessionFactory:是生产SqlSession的工厂。
mybatis 核心配置文件,通常命名为 mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="${driver}"/><property name="url" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${password}"/></dataSource></environment></environments><mappers><mapper resource="org/mybatis/example/BlogMapper.xml"/></mappers>
</configuration>
通过配置文件来获取 sqlSessionFactory。
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
创建mapper接口,也就是dao,mapper接口不需要提供实现类,只需要创建 mapper接口对应的配置文件,或者在接口上使用注解,就可以实现对数据库的操作。
public interface UserMapper {/*** 添加用户信息*/int insertUser();
}
创建 mapper 接口对应的映射文件。
ORM(Object Relationship Mapping)对象关系映射。
对象:Java的实体类对象。
关系:关系型数据库。
映射:二者之间的对应关系。
映射文件命名规则:
- 表所对应的实体类的类名+Mapper.xml,表 t_user,映射的实体类为 User,所对应的映射文件为 UserMapper.xml。一个映射文件对应一个实体类,对应一张表的操作 MyBatis 映射文件用于编写 SQL,访问以及操作表中的数据。
- MyBatis 中可以面向接口操作数据,mapper 接口中的全类名和映射文件的命名空间要一致。接口中方法名要和映射文件中编写SQL的标签的 id 属性保持一致。
<?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.atguigu.mybatis.mapper.UserMapper"><!--int insertUser();--><insert id = "insertUser">insert into t_user values(null,'张三','123',23,'女')</insert>
</mapper>
通过上面的配置就基本搭建了 Mybatis 的开发环境。
在程序中,通过核心配置文件创建出 sqlSessionFactory,通过sqlSessionFactory获取 sqlSession,通过sqlSession,获取一个mapper接口的代理对象。代理对象是一个接口的实例化对象,可以调用mapper接口中的实现方法,mapper接口的方法和对应的配置文件通过namespace和id属性绑定,就可以实现对数据库的操作。
public void testMyBatis() throws IOException {//加载核心配置文件InputStream is = Resources.getResourceAsStream("mybatis-config.xml");//获取SqlSessionFactoryBuilderSqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();//获取sqlSessionFactorySqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);//获取SqlSessionSqlSession sqlSession = sqlSessionFactory.openSession(true);//获取mapper接口对象UserMapper mapper = sqlSession.getMapper(UserMapper.class);//测试功能int result = mapper.insertUser();//提交事务//sqlSession.commit();System.out.println("result:"+result);
}
核心配置文件详解
核心配置文件中的标签必须按照固定的顺序:
properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,
reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?
properties 标签,引入properties文件,此时就可以${属性名}的方式访问属性值
<properties resource="jdbc.properties"></properties>
settings 标签可以设置一些属性,可以参考官方文档进行设置。
<settings><!--将表中字段的下划线自动转换为驼峰--><setting name="mapUnderscoreToCamelCase" value="true"/><!--开启延迟加载--><setting name="lazyLoadingEnabled" value="true"/>
</settings>
typeAliases 设置POJO类的别名。
typeAlias:设置某个具体的类型的别名。
type:需要设置别名的类型的全类名。
alias:设置此类型的别名,若不设置此属性,该类型拥有默认的别名,即类名且不区分大小写若设置此属性,此时该类型的别名只能使用alias所设置的值。
<typeAliases><!--设置单个类的别名 --><typeAlias type="com.atguigu.mybatis.bean.User"></typeAlias><typeAlias type="com.atguigu.mybatis.bean.User" alias="abc"></typeAlias><!--以包为单位,设置改包下所有的类型都拥有默认的别名,即类名且不区分大小写--><package name="com.atguigu.mybatis.bean"/>
</typeAliases>
environments 设置多个连接数据库的环境,default 设置默认使用的环境的 id。
environment 设置具体的连接数据库的环境信息,需要设置事务管理方式,数据源信息。
<environments default="mysql_test"><environment id="mysql_test"><!--transactionManager:设置事务管理方式type:设置事务管理方式,type="JDBC|MANAGED"type="JDBC":设置当前环境的事务管理都必须手动处理type="MANAGED":设置事务被管理,例如spring中的AOP--><transactionManager type="JDBC"/><!--dataSource:设置数据源type:设置数据源的类型,type="POOLED|UNPOOLED|JNDI"type="POOLED":使用数据库连接池,即会将创建的连接进行缓存,下次使用可以从缓存中直接获取,不需要重新创建type="UNPOOLED":不使用数据库连接池,即每次使用连接都需要重新创建type="JNDI":调用上下文中的数据源--><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 设置映入的映射文件。
<mappers><!-- 引入单个文件 --><mapper resource="UserMapper.xml"/><!--以包为单位,将包下所有的映射文件引入核心配置文件注意:此方式必须保证mapper接口和mapper映射文件必须在相同的包下(包结构和目录结构一致)--><package name="com.atguigu.mybatis.mapper"/>
</mappers>
mapper 映射文件(实现增删改查)
一个mapper映射文件对应一个接口,mapper文件中编写sql的标签的对应一个接口的方法。
对数据库的操作有增删改查,mapper文件中的编写sql的标签有查询 select标签,修改update标签,删除delete标签,添加 insert标签。
添加
<!--int insertUser();-->
<insert id="insertUser">insert into t_user values(null,'admin','123456',23,'男')
</insert>
删除
<!--int deleteUser();-->
<delete id="deleteUser">delete from t_user where id = 7
</delete>
修改
<!--int updateUser();-->
<update id="updateUser">update t_user set username='ybc',password='123' where id = 6
</update>
查询单个
<!--User getUserById();-->
<select id="getUserById" resultType="com.atguigu.mybatis.bean.User">select * from t_user where id = 2
</select>
查询集合
<!--List<User> getUserList();-->
<select id="getUserList" resultType="com.atguigu.mybatis.bean.User">select * from t_user
</select>
其中增删改的操作会返回更新的行数,查询操作会返回对应的数据。对于查询需要将返回的数据与对于的POJO类进行映射。
查询的标签 select 必须设置属性 resultType 或 resultMap,用于设置实体类和数据库表的映射关系。
resultType:自动映射,用于属性名和表中字段名一致的情况。
resultMap:自定义映射,用于一对多或多对一或字段名和属性名不一致的情况。
当查询的数据为多条时,不能使用实体类作为返回值,只能使用集合。
MyBatis获取参数值的两种方式
MyBatis获取参数值的两种方式:${} 和 #{}
${} 的本质就是字符串拼接,#{} 的本质就是占位符赋值。
${} 使用字符串拼接的方式拼接sql,若为字符串类型或日期类型的字段进行赋值时,需要手动加单引号;
#{}使用占位符赋值的方式拼接sql,此时为字符串类型或日期类型的字段进行赋值时,可以自动添加单引号;
在映射文件的sql标签中获取接口中传递的参数。
可以通过@Param注解标识mapper接口中的方法参数,会将这些参数放在map集合中,以@Param注解的 value属性值为键,以参数为值。
只需要通过 # {} 和 $ {} 访问map集合的键就可以获取相对应的值,注意${}需要手动加单引号。
如果参数为实体类类型,通过 对象名.属性名 可以获取属性值。
MyBatis的各种查询功能
查询一个实体类对象,通过id来查询一条数据。在接口中使用 @Param 注解,设置属性值。在映射文件中 通过 #{} 的方式获取参数。
resultType 设置 查询结果集的封装类型。其中 封装的类型属性要和表中查询的属性对应(可开启驼峰映射,数据库字段中的下划线转换为驼峰方式)。
<!--User getUserById(@Param("id") int id);-->
<select id="getUserById" resultType="User">select * from t_user where id = #{id}
</select>
查询一个list集合,查询的数据为多条,则接口的返回值要设置为集合类型。
<!--List<User> getUserList();-->
<select id="getUserList" resultType="User">select * from t_user
</select>
查询单个数据
<!--
在MyBatis中,对于Java中常用的类型都设置了类型别名
例如:java.lang.Integer 别名 int|integer
例如:int 别名 _int|_integer
例如:Map 别名 map,List 别名 list
其他可参考官方文档。
-->
<!--int getCount();-->
<select id="getCount" resultType="int">select count(id) from t_user
</select>
查询一条数据为 map 集合,会自动将字段和值放入map集合中。
<!--Map<String, Object> getUserToMap(@Param("id") int id);-->
<select id="getUserToMap" resultType="map">select * from t_user where id = #{id}
</select>
<!--结果:{password=123456, sex=男, id=1, age=23, username=admin}-->
查询多条数据为map集合
将表中的数据以map集合的方式查询,一条数据对应一个map;若有多条数据,就会产生多个map集合,此时可以将这些map放在一个list集合中获取。
<!--Map<String, Object> getAllUserToMap();-->
<select id="getAllUserToMap" resultType="map">select * from t_user
</select>
特殊SQL的执行
${} 的本质就是字符串拼接,#{} 的本质就是占位符赋值。对于有些 sql 只能使用字符串拼接。
模糊查询,如果使#{} 会先进行占位符替换,就会被替换为 ‘%?%’ ,而占位符出现在字符串中,就不能进行值替换。
<!--List<User> testMohu(@Param("mohu") String mohu);-->
<select id="testMohu" resultType="User">select * from t_user where username like '%${mohu}%'<!--select * from t_user where username like concat('%',#{mohu},'%')-->
</select>
批量删除,如果使用 #{} 就会整个替换,并加上了单引号,就达不到想要的结果。
<!--int deleteMore(@Param("ids") String ids);-->
<delete id="deleteMore">delete from t_user where id in (${ids})
</delete>
动态设置表名,#{} 占位符替换后会加上单引号,就会出错。
<!--List<User> getAllUser(@Param("tableName") String tableName);-->
<select id="getAllUser" resultType="User">select * from ${tableName}
</select>
添加功能获取自增的主键
useGeneratedKeys:设置使用自增的主键
keyProperty:指定将主键放入参数的某个属性中。
下面中,自增的主键就会放入 user 的 id 属性中。
<!--int insertUser(User user);-->
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">insert into t_user values(null,#{username},#{password},#{age},#{sex})
</insert>
自定义映射resultMap
若字段名和实体类的属性不一致,可以通过resultMap 设置自定义映射。
resultMap 字段和属性的映射
resultMap:设置自定义映射,id 属性:表示自定义映射的唯一标识,type 属性:查询的数据要映射的实体类的类型。
子标签:
id:设置主键的映射关系。
result:设置普通字段的映射关系。
association:设置多对一的映射关系。
collection:设置一对多的映射关系。
属性:
property:设置映射关系中实体类中的属性名。
column:设置映射关系中表中的字段名。
<resultMap id="userMap" type="User"><id property="id" column="id"></id><result property="userName" column="user_name"></result><result property="password" column="password"></result><result property="age" column="age"></result><result property="sex" column="sex"></result>
</resultMap>
<!--List<User> testMohu(@Param("mohu") String mohu);-->
<select id="testMohu" resultMap="userMap">select id,user_name,password,age,sex from t_user where user_name like concat('%',#{mohu},'%')
</select>
若字段名和实体类中的属性名不一致,但是字段名符合数据库的规则(使用_),实体类中的属性名符合Java的规则(使用驼峰),可以在配置文件中设置一个全局配置信息 mapUnderscoreToCamelCase,自动完成映射。
如:字段名user_name 会自动映射为 userName。
多对一映射处理
在员工信息中存储了部门的信息。
实体类结构如下:
class Emp{// 基本属性String id;...// 部门类Dept dep;
}
可以使用 association 处理映射关系。
association 中 property 属性为实体类中的属性名,javaType 为映射的对象类型。子标签中的id和result 同 resultMap下的作用一致。
<resultMap id="empDeptMap" type="Emp"><id column="eid" property="eid"></id><result column="ename" property="ename"></result><result column="age" property="age"></result><result column="sex" property="sex"></result><association property="dept" javaType="Dept"><id column="did" property="did"></id><result column="dname" property="dname"></result></association>
</resultMap>
<!--Emp getEmpAndDeptByEid(@Param("eid") int eid);-->
<select id="getEmpAndDeptByEid" resultMap="empDeptMap">select emp.*,dept.* from t_emp emp left join t_dept dept on emp.did = dept.did where emp.eid = #{eid}
</select>
使用分步查询完成多对一的映射。
分步查询:使用多个 sql ,共同来完成一个功能。
根据部门id,查出部门信息。
<!--Dept getEmpDeptByStep(@Param("did") int did);-->
<select id="getEmpDeptByStep" resultType="Dept">select * from t_dept where did = #{did}
</select>
使用员工id,查询员工信息和对应的部门信息。先查出员工的所有信息,然后调用 getEmpDeptByStep 接口,将部门id 作为参数,查出部门信息,将部门信息封装到 dept 属性中。
<resultMap id="empDeptStepMap" type="Emp"><id column="eid" property="eid"></id><result column="ename" property="ename"></result><result column="age" property="age"></result><result column="sex" property="sex"></result><!--select:设置分步查询,查询某个属性的值的sql的标识(namespace.sqlId)column:将sql以及查询结果中的某个字段设置为分步查询的条件--><association property="dept" select="com.atguigu.MyBatis.mapper.DeptMapper.getEmpDeptByStep" column="did"></association>
</resultMap>
<!--Emp getEmpByStep(@Param("eid") int eid);-->
<select id="getEmpByStep" resultMap="empDeptStepMap">select * from t_emp where eid = #{eid}
</select>
一对多映射处理
一个部门包含多个员工,在部门实体类中有一个集合来存储所有的员工信息。
使用 collection 完成一对多的映射。collection 中的 property 属性 用来指明实体类中的属性名。ofType 属性,用来指明处理的集合属性中存储的数据的类型。子标签中的id,result 与 resultMap中的标签作用一致。
<resultMap id="deptEmpMap" type="Dept"><id property="did" column="did"></id><result property="dname" column="dname"></result><collection property="emps" ofType="Emp"><id property="eid" column="eid"></id><result property="ename" column="ename"></result><result property="age" column="age"></result><result property="sex" column="sex"></result></collection>
</resultMap>
<!--Dept getDeptEmpByDid(@Param("did") int did);-->
<select id="getDeptEmpByDid" resultMap="deptEmpMap">select dept.*,emp.* from t_dept dept left join t_emp emp on dept.did = emp.did where dept.did = #{did}
</select>
分步查询
根据部门 id 查询员工信息。
<!--List<Emp> getEmpListByDid(@Param("did") int did);-->
<select id="getEmpListByDid" resultType="Emp">select * from t_emp where did = #{did}
</select>
查询出部门信息,使用部门id调用 getEmpListByDid 接口查询出所有员工信息。
collection中 fetchType用来设置是否延迟加载。select 属性查询的全标识,column 指明查询的参数。
<resultMap id="deptEmpStep" type="Dept"><id property="did" column="did"></id><result property="dname" column="dname"></result><collection property="emps" fetchType="eager" select="com.atguigu.MyBatis.mapper.EmpMapper.getEmpListByDid" column="did"></collection>
</resultMap>
<!--Dept getDeptByStep(@Param("did") int did);-->
<select id="getDeptByStep" resultMap="deptEmpStep">select * from t_dept where did = #{did}
</select>
分步查询的优点:可以实现延迟加载。延迟加载指当使用的时候才进行查询相关数据。
使用延迟加载必须在核心配置文件中设置全局配置信息:
lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载
aggressiveLazyLoading:当开启时,任何方法的调用都会加载该对象的所有属性。 否则,每个属性会按需加载。
association和 collection中的fetchType属性设置当前的分步查询是否使用延迟加载,fetchType= lazy(延迟加载) | eager(立即加载)。
在核心配置文件的 settings 中进行配置。
<settings><!--开启延迟加载--><setting name="lazyLoadingEnabled" value="true"/>
</settings>
动态SQL
Mybatis框架的动态SQL技术是一种根据特定条件动态拼装SQL语句的功能,它存在的意义是为了解决拼接SQL语句字符串时的痛点问题。
if 标签可通过test属性的表达式进行判断,若表达式的结果为true,则标签中的内容会执行;反之标签中的内容不会执行。
<!--List<Emp> getEmpListByMoreTJ(Emp emp);-->
<select id="getEmpListByMoreTJ" resultType="Emp">select * from t_emp where 1=1<if test="ename != '' and ename != null">and ename = #{ename}</if><if test="age != '' and age != null">and age = #{age}</if><if test="sex != '' and sex != null">and sex = #{sex}</if>
</select>
where和if一般结合使用:
- 若where标签中的if条件都不满足,则where标签没有任何功能,即不会添加where关键字
- 若where标签中的if条件满足,则where标签会自动添加where关键字,并将条件最前方多余的 and去掉
- where标签不能去掉条件最后多余的and
<select id="getEmpListByMoreTJ2" resultType="Emp">select * from t_emp<where><if test="ename != '' and ename != null">ename = #{ename}</if><if test="age != '' and age != null">and age = #{age}</if><if test="sex != '' and sex != null">and sex = #{sex}</if></where>
</select>
trim用于去掉或添加标签中的内容
常用属性:
- prefix:在trim标签中的内容的前面添加某些内容
- prefixOverrides:在trim标签中的内容的前面去掉某些内容
- suffix:在trim标签中的内容的后面添加某些内容
- suffixOverrides:在trim标签中的内容的后面去掉某些内容
<select id="getEmpListByMoreTJ" resultType="Emp">select * from t_emp<trim prefix="where" suffixOverrides="and"><if test="ename != '' and ename != null">ename = #{ename} and</if><if test="age != '' and age != null">age = #{age} and</if><if test="sex != '' and sex != null">sex = #{sex}</if></trim>
</select>
choose、when、otherwise相当于if…else if…else
可以没有otherwise标签。当满足一个when标签时,就结束。若所有when标签都不满足,有otherwise标签就执行otherwise标签。
<!--List<Emp> getEmpListByChoose(Emp emp);-->
<select id="getEmpListByChoose" resultType="Emp">select <include refid="empColumns"></include> from t_emp<where><choose><when test="ename != '' and ename != null">ename = #{ename}</when><when test="age != '' and age != null">age = #{age}</when><when test="sex != '' and sex != null">sex = #{sex}</when><when test="email != '' and email != null">email = #{email}</when></choose></where>
</select>
foreach 循环遍历,拼接sql。
属性:
- collection:设置要循环的数组或集合
- item:表示集合或数组中的每一个数据
- separator:设置循环体之间的分隔符
- open:设置foreach标签中的内容的开始符
- close:设置foreach标签中的内容的结束符、
<!--int insertMoreEmp(List<Emp> emps);-->
<insert id="insertMoreEmp">insert into t_emp values<foreach collection="emps" item="emp" separator=",">(null,#{emp.ename},#{emp.age},#{emp.sex},#{emp.email},null)</foreach>
</insert>
<!--int deleteMoreByArray(int[] eids);-->
<delete id="deleteMoreByArray">delete from t_emp where eid in<foreach collection="eids" item="eid" separator="," open="(" close=")">#{eid}</foreach>
</delete>
SQL片段,定义一段公共的sql片段,在使用的地方通过include标签进行引入。
<sql id="empColumns">eid,ename,age,sex,did
</sql>
select <include refid="empColumns"></include> from t_emp
MyBatis的缓存
MyBatis的一级缓存
一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问。
使一级缓存失效的四种情况:
- 不同的SqlSession对应不同的一级缓存
- 同一个SqlSession但是查询条件不同
- 同一个SqlSession两次查询期间执行了任何一次增删改操作
- 同一个SqlSession两次查询期间手动清空了缓存
MyBatis的二级缓存
二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取。
二级缓存开启的条件:
- 在核心配置文件中,设置全局配置属性cacheEnabled="true",默认为true,不需要设置。
- 在映射文件中设置标签<cache />
<cache />
- 二级缓存必须在SqlSession关闭或提交之后有效
- 查询的数据所转换的实体类类型必须实现序列化的接口
使二级缓存失效的情况:
两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效。
二级缓存的相关配置
在mapper配置文件中添加的cache标签可以设置一些属性:
- eviction属性:缓存回收策略
LRU(Least Recently Used) – 最近最少使用的:移除最长时间不被使用的对象。
FIFO(First in First out) – 先进先出:按对象进入缓存的顺序来移除它们。
SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
默认的是 LRU。 - flushInterval属性:刷新间隔,单位毫秒,默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。
- size属性:引用数目,正整数,代表缓存最多可以存储多少个对象,太大容易导致内存溢出。
- readOnly属性:只读,true/false
true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。
false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,默认是 false。
MyBatis缓存查询的顺序
- 先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用。
- 如果二级缓存没有命中,再查询一级缓存
- 如果一级缓存也没有命中,则查询数据库
- SqlSession关闭之后,一级缓存中的数据会写入二级缓存
MyBatis的逆向工程
正向工程:先创建Java实体类,由框架负责根据实体类生成数据库表。Hibernate是支持正向工程的。
逆向工程:先创建数据库表,由框架负责根据数据库表,反向生成如下资源:Java实体类,Mapper接口,Mapper映射文件。
创建逆向工程的步骤
- 添加依赖和插件
<!-- 依赖MyBatis核心包 -->
<dependencies><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.7</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><!-- 数据库连接池 --><dependency><groupId>com.mchange</groupId><artifactId>c3p0</artifactId><version>0.9.2</version></dependency><!-- MySQL驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.8</version></dependency></dependencies></plugin></plugins>
</build>
- 创建MyBatis的核心配置文件
- 创建逆向工程的配置文件,文件名必须是:generatorConfig.xml
<?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="MyBatis3Simple"><!-- 数据库的连接信息 --><jdbcConnection driverClass="com.mysql.jdbc.Driver"connectionURL="jdbc:mysql://localhost:3306/mybatis"userId="root"password="123456"></jdbcConnection><!-- javaBean的生成策略--><javaModelGenerator targetPackage="com.atguigu.mybatis.bean"targetProject=".\src\main\java"><property name="enableSubPackages" value="true" /><property name="trimStrings" value="true" /></javaModelGenerator><!-- SQL映射文件的生成策略 --><sqlMapGenerator targetPackage="com.atguigu.mybatis.mapper"targetProject=".\src\main\resources"><property name="enableSubPackages" value="true" /></sqlMapGenerator><!-- Mapper接口的生成策略 --><javaClientGenerator type="XMLMAPPER"targetPackage="com.atguigu.mybatis.mapper" targetProject=".\src\main\java"><property name="enableSubPackages" value="true" /></javaClientGenerator><!-- 逆向分析的表 --><!-- tableName 设置为*号,可以对应所有表,此时不写domainObjectName --><!-- domainObjectName 属性指定生成出来的实体类的类名 --><table tableName="t_emp" domainObjectName="Emp"/><table tableName="t_dept" domainObjectName="Dept"/></context>
</generatorConfiguration>
- 执行MBG插件的generate目标,就会根据配置文件生成实体类,mapper接口和映射文件。
生成结果
QBC查询
生成的xxxExample类中,可以设置各种各样的条件查询。
@Test
public void testMBG() throws IOException {InputStream is = Resources.getResourceAsStream("mybatis-config.xml");SqlSession sqlSession = new SqlSessionFactoryBuilder().build(is).openSession(true);EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);EmpExample empExample = new EmpExample();//创建条件对象,通过andXXX方法为SQL添加查询添加,每个条件之间是and关系empExample.createCriteria().andEnameLike("a").andAgeGreaterThan(20).andDidIsNotNull();//将之前添加的条件通过or拼接其他条件empExample.or().andSexEqualTo("男");List<Emp> list = mapper.selectByExample(empExample);for (Emp emp : list) {System.out.println(emp);}
}
分页插件
分页插件使用步骤
- 添加依赖
<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.2.0</version>
</dependency>
- 配置分页插件,在MyBatis的核心配置文件中配置插件。
<plugins><!--设置分页插件--><plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
使用分页插件。
- 在查询功能之前使用 PageHelper.startPage(int pageNum, int pageSize) 开启分页功能,pageNum:当前页的页码,pageSize:每页显示的条数。
- 在查询获取list集合之后,使用PageInfo pageInfo = new PageInfo<>(List list, int navigatePages)获取分页相关数据。list:分页之后的数据,navigatePages:导航分页的页码数。
分页相关数据
PageInfo{pageNum=8, pageSize=4, size=2, startRow=29, endRow=30, total=30, pages=8,list=Page{count=true, pageNum=8, pageSize=4, startRow=28, endRow=32, total=30,pages=8, reasonable=false, pageSizeZero=false},prePage=7, nextPage=0, isFirstPage=false, isLastPage=true, hasPreviousPage=true,hasNextPage=false, navigatePages=5, navigateFirstPage4, navigateLastPage8,navigatepageNums=[4, 5, 6, 7, 8]
}
常用数据:
pageNum:当前页的页码
pageSize:每页显示的条数
size:当前页显示的真实条数
total:总记录数
pages:总页数
prePage:上一页的页码
nextPage:下一页的页码
isFirstPage/isLastPage:是否为第一页/最后一页
hasPreviousPage/hasNextPage:是否存在上一页/下一页
navigatePages:导航分页的页码数
navigatepageNums:导航分页的页码,[1,2,3,4,5]
示例代码
@Test
public void testPageHelper(){try {InputStream is = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);SqlSession sqlSession = sqlSessionFactory.openSession(true);EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);// Page<Object> page = PageHelper.startPage(2, 4);// 查询之前设置分页PageHelper.startPage(6, 4);// list 为设置分页后,当前页的数据List<Emp> list = mapper.selectByExample(null)// 根据查询结果获取分页相关数据PageInfo<Emp> page = new PageInfo<>(list, 5);// list.forEach(emp -> System.out.println(emp));// pageInfo 中包含所有分页相关的数据,可以返回前端,进行展示。 System.out.println(page);} catch (IOException e) {e.printStackTrace();}
}
相关文章:

MyBatis 框架
MyBatis 框架 MyBatis 简介搭建 MyBatis 开发环境核心配置文件详解mapper 映射文件(实现增删改查)MyBatis获取参数值的两种方式MyBatis的各种查询功能特殊SQL的执行自定义映射resultMapresultMap 字段和属性的映射多对一映射处理一对多映射处理 动态SQLM…...

【C++】虚表和虚基表到底有哪些区别?
虚表和虚基表 虚表虚基表虚拟继承和虚函数都存在时的对象模型 虚表 我们知道,如果类中声明了的方法是用virtual进行修饰的,则说明当前这个方法要作为虚函数,而虚函数的存储和普通函数的存储是有区别的 当有虚函数声明时,编译器会…...

剑指 Offer 04. 二维数组中的查找解题思路
文章目录 标题解题思路优化 标题 在一个 n * m 的二维数组中,每一行都按照从左到右 非递减 的顺序排序,每一列都按照从上到下 非递减 的顺序排序。请完成一个高效的函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整…...

冯诺依曼体系结构详解
一.冯诺伊曼体系结构的概念: 约翰冯诺依曼(John von Neumann,1903.1.28-1957.2.8),美籍匈牙利数学家,计算机科学家,物理学家。是20世纪最重要的数学家之一,后来被称为计算机之父。 后…...

ISO证书“带标”与“不带标”的区别是什么?
ISO9001质量管理体系认证是企业产品获得“通行绿卡”的最直接最有效的途径。 通过认证在打破贸易壁垒,提高产品知名度,降低生产成本,提高经济效益,维护消费者权益,减少重复审核负担等方面的作用越来越为企业界所共知。…...

RocketMQ 领域模型概述
本文为您介绍 Apache RocketMQ 的领域模型。 Apache RocketMQ 是一款典型的分布式架构下的中间件产品,使用异步通信方式和发布订阅的消息传输模型。通信方式和传输模型的具体说明,请参见下文通信方式介绍和消息传输模型介绍。 Apache RocketMQ 产品具备…...

黄河千年清一回与人类健康
黄河千年清一回奏响一曲曲让人类走进幸福新时代的壮丽凯歌。疫情之后的首届全世界健康产业发展大会 5 月28 日上午 9 时在中国首都北京召开 The Yellow River has played a magnificent song of triumph in the millennium, ushering humanity into a new era of happiness. T…...

Android java层hook------xposed框架的使用
xposed曾经是android平台上最好的java层hook和调试工具,由于已经不再更新,当前支持的android系统版本比较老旧,目前只能支持到android6.0,故已经逐渐落伍,目前android上最广泛使用的hook工具是frida,这是另…...

css奇淫巧计
1.input文本内容替换 -webkit-text-security:通过用形状替换字符,仅影响那些字段不是的typepassword 可选值:none (无),circle (圆圈),disc (圆形),square &a…...

Web服务器实现|基于阻塞队列线程池的Http服务器|线程控制|Http协议
基于阻塞队列生产者消费者模型线程池的多线程Web服务器 代码地址:WebServer_GitHub_Addr README 摘要 本实验通过C语言,实现了一个基于阻塞队列线程池的多线程Web服务器。该服务器支持通过http协议发送报文,跨主机抓取服务器上特定资源。与…...

【C++】运算符重载(日期类的实现)
【C】运算符重载(日期类的实现) 前言运算符重载operator全局和类中 日期类的实现成员变量的确定构造函数拷贝构造 运算符重载部分的重载思路实现GETmonthdayoperator 的重载思路实现 -的与-的重载实现 各个比较运算符的重载实现 前置与后置实现 …...

【Linux】线程分离 | 线程库 | C++调用线程 | 线程局部存储
文章目录 1. 线程分离1. 为什么要线程分离?2. 具体使用3. 为什么有时候分离在调用join 会正常运行? 2. 如何理解线程库?如何理解 先描述 在组织? 3. C中使用多线程4. 线程局部存储局部变量全局变量 1. 线程分离 1. 为什么要线程分…...

c++ ffmpeg 浅谈YUV444、YUV422、YUV420(2)
本期将会给大家介绍YUV相关基础知识,同时也介绍威创网络分布式系统的卓越色彩处理技术。 1.什么是YUV色彩空间 2.YUV采样格式 3.YUV不同采样格式对图像画质的影响分析 一、什么是YUV色彩空间? YUV是视频、图片、相机等应用中常常使用的一类图像格式,是…...

Redis在Windows下安装配置教程
Redis是一个开源的高性能键值对存储数据库,常用于缓存、消息队列等场景。本文将介绍如何在Windows系统下安装配置Redis。 1. 下载地址 Redis官方网站提供了Windows版本的安装包下载地址,网址为:https://github.com/tporadowski/redis/relea…...

数据库服务器
数据库服务器,联系Web服务器与DBMS的中间件是负责处理所有的应用程序服务器,包括在web服务器和后台的应用程序或数据库之间的事务处理和数据访问。 基本信息 中文名 数据库服务器 外文名 database server 功能 数据库服务器建立在数据库系统基础上&a…...

VS输出路径和生成事件
在生成时,常常希望输出文件夹整洁,因此需要设置dll或exe输出位置,同时也希望对一些文件做一些特殊操作 VS的 UI 常用缩写 “./”:代表目前所在的目录。 " . ./"代表上一层目录。 “/”:代表根目录。 生成…...

从 WebKit 看浏览器内核架构
浏览器常见的浏览器内核有:Blink、WebKit、Gecko、Trident 等,目前 WebKit 内核占据了非常大的的市场,包括 Chrome、Safari、安卓浏览器等市面上的主流浏览器,都使用了 WebKit 内核。 从 WebKit 看浏览器内核架构 既然 WebKit 这么…...

使用原生的 JavaScript,不依赖于任何特定的库与 ROSBridge进行通信
使用原生的 JavaScript,不依赖于任何特定的库与 ROSBridge进行通信 创建与 ROS 的连接: var rosbridge_url "ws://localhost:9090"; var ws new WebSocket(rosbridge_url);ws.onopen function(event) {console.log(Connected to rosbri…...

MATLAB第十章_图像处理算法
目录 图像处理算法 图像处理基础 图像处理函数 默认显示方式 添加颜色条 显示多帧图像 显示动画 三维材质图像 图像的直方图 灰度变换 均衡直方图 图像处理应用 图像增强 图像重建 图像变换 图像压缩 图像分割 图像边缘检测 图像识别 图像处理算法 图像处理…...

RobotFramework接口测试方案
1. Robot FrameWork介绍 1.1 介绍 Robot Framework是用于验收测试和回归测试的通用测试自动化框架。它使用易于理解的表格数据语法,非常友好的实现了关键字驱动和数据驱动模式。它的测试功能可以通过使用Python或Java实现的测试库进行扩展,用户可以使用…...

chatgpt赋能python:Python中日期转换:从字符串到日期对象
Python中日期转换:从字符串到日期对象 作为一个经验丰富的Python工程师,日期转换在我的日常编码工作中经常遇到。Python提供了一些内置函数和模块,可以将字符串转换为日期对象或将日期对象格式化为特定的字符串。本篇文章将带您深入了解Pyth…...

k8s 1.27新特性in-place使用方法:避坑指南(官方文档有坑,已提issue)
背景 按照官方文档试用新版的in-place特性时,一字不差地执行了,但是却出现了执行失败的情况: 执行kubectl -n qos-example patch pod qos-demo-5 --patch {"spec":{"containers":[{"name":"qos-demo-ct…...

网络传输(传输介质、通信方式、交换方式)
目录 一、传输介质1.双绞线2.网线安装3.光纤4.无线信道 二、通信方式、交换方式1.通信方式2.同步方式3.交换方式 一、传输介质 1.双绞线 双绞线:将多根铜线按规则缠绕在一起,能够减少干扰;分为无屏蔽双绞线UTP和屏蔽双绞线STP,都…...

【Unity】Time.deltaTime有什么用?看完你就明白
大多数刚开始使用 Unity 的人(包括我),都会对Time.deltaTime感到迷惑。 看完本文,你就会明白Time.deltaTime的定义及作用。 1、deltaTime是什么? 根据定义,Time.deltaTime是每一帧之间的时间间隔(以秒为单位)。 这有助于我们使游戏与帧数无关,也就是说,无论 fps 是…...

vue实现用户动态权限登录
一、使用vueelementUI搭登录框架,主要就是1、2、3、4 配置: ①vue.config.js use strict const path require(path)function resolve(dir) {return path.join(__dirname, dir) }// All configuration item explanations can be find in https://cli.v…...

ONNX模型修改为自定义节点
参考一 首先,需要将ONNX模型中的节点修改为自定义节点。要实现这一点,您需要了解自定义节点的定义和如何在ONNX中使用它们。ONNX定义了一个自定义运算符的接口,您可以使用该接口定义自己的运算符,并将其编译为ONNX模型可以识别的…...

内存对齐原则
struct (1)结构体第一个数据成员放在offset为0的地方,后面每个成员相对于结构体首地址的偏移量(offset)都是成员大小(该变量类型所占字节)的整数倍,如有需要编译器会在成员之间加上填…...

Java SPI 一 之SPI(Service Provider Interface)进阶 AutoService
一、SPI(Service Provider Interface) 1.1 介绍 SPI(Service Provider Interface),是JDK内置的一种 服务提供发现机制(为某个接口寻找服务实现的机制),可以用来启用框架扩展和替换组件,其…...

C++ list类成员函数介绍
目录 🤔list模板介绍: 🤔特点: 🤔list内存结构图解: 🤔 list的成员函数: 😊list构造函数: 🔍代码示例: 🔍运行结果&…...

【服务器】本地搭建PHP简单Imagewheel私人云图床
文章目录 1.前言2. Imagewheel网站搭建2.1. Imagewheel下载和安装2.2. Imagewheel网页测试2.3.cpolar的安装和注册 3.本地网页发布3.1.Cpolar临时数据隧道3.2.Cpolar稳定隧道(云端设置)3.3.Cpolar稳定隧道(本地设置) 4.公网访问测…...