MyBatis 框架

news2024/11/22 16:21:35

MyBatis 框架

  • MyBatis 简介
  • 搭建 MyBatis 开发环境
  • 核心配置文件详解
  • mapper 映射文件(实现增删改查)
  • MyBatis获取参数值的两种方式
  • MyBatis的各种查询功能
  • 特殊SQL的执行
  • 自定义映射resultMap
    • resultMap 字段和属性的映射
    • 多对一映射处理
    • 一对多映射处理
  • 动态SQL
  • MyBatis的缓存
  • MyBatis的逆向工程
  • 分页插件

MyBatis 简介

MyBatis 是一个基于Java 的持久层框架。

  1. MyBatis 支持定制化SQL,存储过程以及高级映射,是一个非常优秀的持久层框架。
  2. MyBatis 对JDBC的设置参数和获取结果集的操作进行封装。
  3. MyBatis 可以使用xml或注解用于配置和原始映射,将接口和Java的POJO映射成数据库中的记录。
  4. 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");
    //获取SqlSessionFactoryBuilder
    SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
    //获取sqlSessionFactory
    SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
    //获取SqlSession
    SqlSession 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缓存查询的顺序

  1. 先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用。
  2. 如果二级缓存没有命中,再查询一级缓存
  3. 如果一级缓存也没有命中,则查询数据库
  4. SqlSession关闭之后,一级缓存中的数据会写入二级缓存

MyBatis的逆向工程

正向工程:先创建Java实体类,由框架负责根据实体类生成数据库表。Hibernate是支持正向工程的。
逆向工程:先创建数据库表,由框架负责根据数据库表,反向生成如下资源:Java实体类,Mapper接口,Mapper映射文件。

创建逆向工程的步骤

  1. 添加依赖和插件
<!-- 依赖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>
  1. 创建MyBatis的核心配置文件
  2. 创建逆向工程的配置文件,文件名必须是: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>
  1. 执行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);
	}
}

分页插件

分页插件使用步骤

  1. 添加依赖
<dependency>
	<groupId>com.github.pagehelper</groupId>
	<artifactId>pagehelper</artifactId>
	<version>5.2.0</version>
</dependency>
  1. 配置分页插件,在MyBatis的核心配置文件中配置插件。
<plugins>
	<!--设置分页插件-->
	<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>

使用分页插件。

  1. 在查询功能之前使用 PageHelper.startPage(int pageNum, int pageSize) 开启分页功能,pageNum:当前页的页码,pageSize:每页显示的条数。
  2. 在查询获取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();
   }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/565980.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

11 - YOLO算法二 (目标检测)

要点&#xff1a; 三 YOLO v3 3.1 Darknet-53 &#xff08;backbone&#xff09; 3.2 目标边界框的预测 将预测的边界框中心限制在当前cell中&#xff0c; s(x) Sigmoid(x) 。 3.3 正负样本的匹配 3.4 损失的计算 3.4.1 置信度损失 (Binary Cross Entropy) 其中 表示预测…

能耗监测系统在淼泉卫生院项目的应用

摘要&#xff1a;随着社会生活水平的提高&#xff0c;经济的繁荣发展&#xff0c;人们对能源的需求逐渐增长&#xff0c;由此带来的能源危机日益严重。办公建筑、医院、商场等场所如何实时的了解、分析和控制能源消耗已成为需要解决的迫在眉睫的难题。传统的能源消耗只能以月/季…

CPU性能优化:分支预测

条件跳转引起的控制冒险虽然也可以通过在流水线中插入空泡来避免&#xff0c;但是当流水线很深时&#xff0c;需要插入更多的空泡。一个20级的流水线为例&#xff0c;如果一条指令需要上一条指令的执行结束才能执行&#xff0c;则需要在这两条指令之间插入19个空泡&#xff0c;…

STL详解— list类的模拟实现

本文章所需实现三个类及其每个类里的各个函数接口总览&#xff1a; namespace zhc {//模拟实现list当中的结点类template<class T>struct list_node{//成员函数list_node(const T& val T()); //构造函数//成员变量T _val; //数据域list_node<T&g…

推荐系统简介

文章目录 推荐系统的分类基于人口统计学的推荐算法基于内容的推荐算法基于协同过滤的推荐算法协同过滤&#xff08;CF&#xff09;推荐方法基于近邻基于用户的协同过滤基于物品的协同过滤 混合推荐推荐系统实验方法离线实验用户调查在线实验 学习下b站上尚硅谷的推荐系统的课程…

易观千帆 | 2023年4月证券APP月活跃用户规模盘点

易观&#xff1a;2023年4月证券服务应用活跃人数13924.88万人&#xff0c;相较上月&#xff0c;环比下降1.46%&#xff0c;同比增长3.64%&#xff1b;2023年4月自营类证券服务应用Top10 活跃人数6144.02万人&#xff0c;环比下降0.01%&#xff1b;2023年4月第三方证券服务应用T…

「远程开发」VSCode使用SSH远程linux服务器 - 公网远程连接(1)

文章目录 前言视频教程1、安装OpenSSH2、vscode配置ssh3. 局域网测试连接远程服务器4. 公网远程连接4.1 ubuntu安装cpolar内网穿透4.2 创建隧道映射4.3 测试公网远程连接 5. 配置固定TCP端口地址5.1 保留一个固定TCP端口地址5.2 配置固定TCP端口地址5.3 测试固定公网地址远程 转…

chatgpt赋能python:PythonWorkon-使Python多环境管理更加轻松

Python Workon - 使Python多环境管理更加轻松 Python是一种广泛使用的高级编程语言&#xff0c;在众多开发者中应用广泛。在实际工作中&#xff0c;我们有时需要使用不同版本的Python或不同的环境来开发不同的项目。这时候就需要一个Python环境管理器来帮助我们快速地进行环境…

chatgpt赋能python:PythonWSDL:实现更好的Web服务和集成

Python WSDL&#xff1a;实现更好的Web服务和集成 在现代的互联网世界中&#xff0c;我们面临着不断增长的需求&#xff0c;需要实现与不同系统之间的交互和数据共享。Web服务是一种解决方案&#xff0c;允许应用程序通过互联网相互通信。其中Web服务描述语言&#xff08;WSDL…

python+django在线音乐分享网站系统vue_6045i.

本系统主要包括管理员和用户&#xff1a;主要包括个人中心、用户管理、通知公告管理、音乐类型管理、音乐分享管理、音乐榜单管理、音乐论坛、系统管理等功能的管理系统。 (1)绪论 系统的开发背景&#xff0c;意义和系统状况等&#xff0c;详细讲述了系统的用处&#xff0c;对本…

iOS App外包开发解决闪退问题

在iOS应用开发中&#xff0c;闪退&#xff08;应用程序意外退出&#xff09;是一个常见的问题。为了查找和解决闪退问题&#xff0c;可以使用以下工具和方法。今天和大家分享这方面的知识&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开…

扬州晶澳-年产3GW高性能太阳能光伏组件项目Acrel-3000WEB电能管理系统的设计及应用

摘要&#xff1a;在信息时代&#xff0c;电力信息系统的应用促迚了电力企业的収展&#xff0c;增强了电力系统运行的安全性与稳定性&#xff0c;对满足用户需求其有重要意义。随着国家电网改革政策的逐步推进和落实&#xff0c;Acrel-3000WEB电能管理系统运用互联网和大数据技术…

数据库索引结构(4)---基于B+树的查询

回顾我们学习的线性和课扩展哈希 他们都只能进行等值操作 但是不能进行区间操作 为了进行区间操作和关系的比较和速度考虑 引入数据结构B树 序言:磁盘存储 1. mysql面试题-深入理解B树原理_哔哩哔哩_bilibili 信息是存取在磁盘块中的每个 磁盘最小的存取单位是512KB 要定位磁…

多态的原理、单继承和多继承的虚函数表、以及虚函数表的打印。

一、多态原理 1、下面这个结果是多少&#xff1f; class A { public:virtual void func(){cout << "func()" << endl;}private:int _a 1; };int main() {printf("%d\n", sizeof(A));return 0; } 是 4&#xff1f;8&#xff1f;还是多少&am…

Python星际生存小游戏开发

项目介绍&#xff1a; 项目名称&#xff1a;python星际生存游戏 编程语言&#xff1a;python 用到关键知识&#xff1a;pygame模块&#xff0c;面向对象思想&#xff0c;python基础等等 实现功能&#xff1a; 1&#xff1a;飞机的运动&#xff0c;发射子弹&#xff0c;飞机…

深入探索Apache Flume:大数据领域的数据采集神器【上进小菜猪大数据系列】

&#x1f4ec;&#x1f4ec;我是上进小菜猪&#xff0c;沈工大软件工程专业&#xff0c;爱好敲代码&#xff0c;持续输出干货&#xff0c;欢迎关注。 引言&#xff1a; 随着大数据技术的快速发展&#xff0c;企业和组织需要从各种来源采集海量数据。数据采集是大数据处理流程中…

DTO、VO、BO、PO、DO理解等相关的转换

1、什么是DTO、VO、BO、PO、DO、POJO pojo(domain/entity)一般定义实体类&#xff0c;实体类又被分为VO、BO、 PO、 DTO、DO&#xff1b;通过各层POJO的使用&#xff0c;有助于提高代码的可读性和可维护性。 2、阿里巴巴Java开发规范 DO(Data Object):此对象与数据库表结构一…

chatgpt赋能python:Python的BeautifulSoup库和find_all()方法

Python的Beautiful Soup库和find_all()方法 在Web爬虫中&#xff0c;我们需要从网页中找到特定的HTML标记或属性&#xff0c;以便提取我们需要的数据。对于Python开发人员而言&#xff0c;Beautiful Soup是最流行的解析HTML和XML的库之一。该库可以让我们轻松地从HTML解析器中…

ECMAScript 6 新特性详解

目录 ECMAScript 6 简介 1、箭头函数 2、类 3、增强对象字面量 4、模板字符串 5、解构赋值 6、默认参数、剩余参数、展开操作符 7、let、const 8、迭代器&#xff08;迭代器&#xff09;、for of 9、Generators&#xff08;生成器&#xff09; 10、Unicode 11、模块…