zoukankan      html  css  js  c++  java
  • MyBatis框架(二)

    一、基于代理Dao实现CRUD操作

    1. 根据ID查询用户信息

    (1)在持久层接口中添加 findById 方法:

    User findById(Integer userId);
    

    (2)在映射文件中配置:

    <!-- 根据 id 查询 --> 
    <select id="findById" resultType="com.itheima.domain.User" parameterType="int">
    	select * from user where id = #{uid}
    </select>
    

    ​ resultType 属性:用于指定结果集的类型。

    ​ parameterType 属性:用于指定传入参数的类型。

    ​ #{uid}:用来接收传入的参数。

    (3)在测试类中添加测试方法:

    public class MybastisCRUDTest {
        private InputStream in ;
        private SqlSessionFactory factory;
        private SqlSession session;
        private IUserDao userDao;
        @Test
        public void testFindOne() {
            //6.执行操作
            User user = userDao.findById(41);
            System.out.println(user);
        }
        @Before//在测试方法执行之前执行
        public void init()throws Exception {
            //1.读取配置文件
            in = Resources.getResourceAsStream("SqlMapConfig.xml");
            //2.创建构建者对象
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            //3.创建 SqlSession 工厂对象
            factory = builder.build(in);
            //4.创建 SqlSession 对象
            session = factory.openSession();
            //5.创建 Dao 的代理对象
            userDao = session.getMapper(IUserDao.class);
        }
        @After//在测试方法执行完成之后执行
    	public void destroy() throws Exception{
            session.commit();
            //7.释放资源
            session.close();
            in.close();
    	} 
    }
    

    2. 新增用户信息

    (1)在持久层接口中添加插入方法:

    /**
    * 保存用户
    * @param user
    * @return 影响数据库记录的行数
    */
    int insertUser(User user);
    

    (2)在映射文件中配置:

    <!-- 新增用户--> 
    <insert id="insertUser" parameterType="com.itheima.domain.User">
    	insert into user(username,birthday,sex,address) values(#{username},#{birthday},#	{sex},#{address})
    </insert>
    

    (3)在测试类中添加测试方法:

    @Test
    public void testSave(){
        User user = new User();
        user.setUsername("张三");
        user.setAddress("北京市顺义区");
        user.setSex("男");
        user.setBirthday(new Date());
        System.out.println("插入操作之前:"+user);
        // 执行插入方法
        userDao.insertUser(user);
        System.out.println("插入操作之后:"+user);
    }
    /*
    	打开 MySQL 数据库发现并没有添加任何记录,原因是什么?这一点和 JDBC 是一样的,我们在实现增删改时一	  定要去控制事务的提交,那么在 MyBatis 中如何控制事务提交呢?可以使用:session.commit();来实现事务提交。
    */
    @After//在测试方法执行完成之后执行
    public void destroy() throws Exception{
        session.commit();
        // 释放资源
        session.close();
        in.close();
    }
    

    3. 更新用户信息

    (1)在持久层接口中添加更新方法:

    /**
    * 更新用户
    * @param user
    * @return 影响数据库记录的行数
    */
    int updateUser(User user);
    

    (2)在映射文件中配置:

    <!-- 更新用户 --> 
    <update id="updateUser" parameterType="com.itheima.domain.User">
    	update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#		{address} where id=#{id}
    </update>
    

    (3)在测试类中添加测试方法:

    @Test
    public void testUpdateUser() throws Exception{
        //1.根据 id 查询
        User user = userDao.findById(52);
        //2.更新操作
        user.setAddress("北京市顺义区");
        int res = userDao.updateUser(user);
        System.out.println(res);
    }
    

    4. 删除用户信息

    (1)在持久层接口中添加删除方法:

    /**
    * 根据 id 删除用户
    * @param userId
    * @return
    */
    int deleteUser(Integer userId);
    

    (2)在映射文件中配置:

    <!-- 删除用户 --> 
    <delete id="deleteUser" parameterType="java.lang.Integer">
    	delete from user where id = #{uid}
    </delete>
    

    (3)在测试类中添加测试方法:

    @Test
    public void testDeleteUser() throws Exception {
        int res = userDao.deleteUser(52);
        System.out.println(res);
    }
    

    5. 模糊查询

    (1)在持久层接口中添加模糊查询方法:

    /**
    * 根据名称模糊查询
    * @param username
    * @return
    */
    List<User> findByName(String username);
    

    (2)在映射文件中配置:

    <!-- 根据名称模糊查询 --> 
    <select id="findByName" resultType="com.itheima.domain.User" parameterType="String">
    	select * from user where username like #{username}
    </select>
    

    (3)在测试类中添加测试方法:

    @Test
    public void testFindByName(){
        List<User> users = userDao.findByName("%王%");
        for(User user : users){
        	System.out.println(user);
        }
    }
    

    6. 使用聚合函数查询

    (1)在持久层接口中添加查询方法:

    /**
    * 查询总记录条数
    * @return
    */
    int findTotal();
    

    (2)在映射文件中配置:

    <!-- 查询总记录条数 --> 
    <select id="findTotal" resultType="int">
    	select count(*) from user;
    </select>
    

    (3)在测试类中添加测试方法:

    @Test
    public void testFindTotal() throws Exception {
        int res = userDao.findTotal();
        System.out.println(res);
    }
    

    二、MyBatis的动态 SQL 语句

    1. < if >标签

    ​ 我们根据实体类的不同取值,使用不同的 SQL 语句来进行查询。比如在 username 不为空时可以根据 username 查询,如果 address 不为空时还要加入 address 作为查询条件。这种情况在我们的多条件组合查询中经常会碰到。

    (1)持久层Dao接口:

    /**
    * 根据用户信息,查询用户列表
    * @param user
    * @return
    */
    List<User> findByUser(User user);
    

    (2)映射配置文件:

    <select id="findByUser" resultType="user" parameterType="user">
        select * from user where 1=1
        <if test="username != null and username != '' ">
        	and username like #{username}
        </if> 
        <if test="address != null">
        	and address like #{address}
        </if>
    </select>
    

    【注】< if >标签的 test 属性中写的是对象的属性名。

    (3)测试:

    @Test
    public void testFindByUser() {
        User u = new User();
        u.setUsername("%王%");
        u.setAddress("%顺义%");
        List<User> users = userDao.findByUser(u);
        for(User user : users) {
        	System.out.println(user);
    	} 
    }
    

    2. < where >标签

    ​ 为了简化上面 where 1=1 的条件拼装,我们可以采用< where >标签来简化开发。

    映射配置文件:

    <!-- 根据用户信息查询 --> 
    <select id="findByUser" resultType="user" parameterType="user"> 
    	<include refid="defaultSql"></include> 
        <where> 
            <if test="username != null and username != '' ">
                and username like #{username}
            </if> 
            <if test="address != null">
                and address like #{address}
            </if>
        </where>
    </select>
    

    3. < foreach >标签

    (0)需求:

    ​ 传入多个 id 查询用户信息,用下边两个 SQL 实现:

    SELECT * FROM USERS WHERE username LIKE '%张%' AND (id =10 OR id =89 OR id=16)

    SELECT * FROM USERS WHERE username LIKE '%张%' AND id IN (10,89,16)

    ​ 这样我们在进行范围查询时,就要将一个集合中的值,作为参数动态添加进来。那么我们将如何进行参数的传递呢?

    (1)在 QueryVo 中加入一个 List 集合用于封装参数:

    public class QueryVo implements Serializable {
    	private List<Integer> ids;
    	public List<Integer> getIds() {
    		return ids; 
    	}
    	public void setIds(List<Integer> ids) {
    		this.ids = ids; 
    	} 
    }
    

    (2)持久层Dao接口:

    /**
    * 根据 id 集合查询用户
    * @param vo
    * @return
    */
    List<User> findInIds(QueryVo vo);
    

    (3)映射配置文件:

    <!-- 查询所有 id 在 id 集合之中的用户 --> 
    <select id="findInIds" resultType="user" parameterType="queryvo">
    	<include refid="defaultSql"></include> 
    	<where> 
    		<if test="ids != null and ids.size() > 0"> 
    			<foreach collection="ids" open="id in (" close=")" item="uid" 	  separator=",">
    				#{uid}
    			</foreach>
    		</if>
    	</where>
    </select>
    

    < foreach >标签用于遍历集合,它的属性:

    ​ collection:代表要遍历的集合

    ​ open:代表where子句的开始部分

    ​ close:代表where子句的结束部分

    ​ item:代表遍历集合的每个元素,生成的变量名

    ​ sperator:代表分隔符

    (4)测试:

    @Test
    public void testFindInIds() {
        QueryVo vo = new QueryVo();
        List<Integer> ids = new ArrayList<>();
        ids.add(41);
        ids.add(42);
        ids.add(43);
        ids.add(46);
        ids.add(57);
        vo.setIds(ids);
        List<User> users = userDao.findInIds(vo);
        for(User user : users) {
        	System.out.println(user);
    	} 
    }
    

    4. < include >标签

    ​ SQL 中可将重复的 SQL 提取出来,使用时用 < include > 标签引用即可,最终达到 SQL 重用的目的。

    (1)定义代码片段:

    <!-- 抽取重复的代码片段 --> 
    <sql id="defaultSql">
    	select * from user
    </sql>
    

    (2)引用代码片段:

    <!-- 查询所有用户信息 --> 
    <select id="findAll" resultType="user"> 
    	<include refid="defaultSql"></include>
    </select>
    
    <!-- 根据 id 查询用户信息 --> 
    <select id="findById" resultType="user" parameterType="int">
    	<include refid="defaultSql"></include>
    	where id = #{uid}
    </select>
    

    三、MyBatis的多表查询

    ​ 本次案例主要以最为简单的用户和账户的模型来分析 MyBatis 的多表关系。用户为 User 表,账户为Account表。一个用户(User)可以有多个账户(Account)。

    注意:

    ​ 因为一个账户信息只能供某个用户使用,所以从查询账户信息出发关联查询用户信息为一对一查询。如果从用户信息出发查询用户下的账户信息则为一对多查询,因为一个用户可以有多个账户。

    1. 一对一查询

    (0)需求:

    ​ 查询所有账户信息,关联查询用户信息。

    (1)修改 Account 类:

    ​ 在 Account 类中加入 User 类的对象作为 Account 类的一个属性。

    public class Account implements Serializable {
    	private Integer id;
        private Integer uid;
        private Double money;
        private User user;
        public User getUser() {
        	return user;
        }
        public void setUser(User user) {
        	this.user = user;
        }
        public Integer getId() {
        	return id; 
        }
        public void setId(Integer id) {
        	this.id = id; 
        }
        public Integer getUid() {
        	return uid; 
        }
        public void setUid(Integer uid) {
        	this.uid = uid; 
        }
        public Double getMoney() {
        	return money; 
        }
        public void setMoney(Double money) {
        	this.money = money; 
        }
        @Override
        public String toString() {
        	return "Account [id=" + id + ", uid=" + uid + ", money=" + money + "]"; 
        } 
    }
    

    (2)持久层Dao接口:

    public interface IAccountDao {
        /**
        * 查询所有账户,同时获取账户的所属用户名称以及他的地址信息
        * @return
        */
        List<Account> findAll();
    }
    

    (3)映射配置文件:

    <?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.itheima.dao.IAccountDao">
        
        <!-- 建立对应关系 --> 
        <resultMap type="account" id="accountMap"> 
            <id column="aid" property="id"/>
            <result column="uid" property="uid"/>
            <result column="money" property="money"/>
            <!-- 它是用于指定从表方的引用实体属性的 --> 
            <association property="user" javaType="user"> 
                <id column="id" property="id"/>
                <result column="username" property="username"/>
                <result column="sex" property="sex"/>
                <result column="birthday" property="birthday"/>
                <result column="address" property="address"/>
            </association>
        </resultMap> 
        
        <select id="findAll" resultMap="accountMap">
        	select u.*,a.id as aid,a.uid,a.money from account a,user u where a.uid =u.id;
        </select>
    </mapper>
    

    (4)测试:

    @Test
    public void testFindAll() {
    	List<Account> accounts = userDao.findAll();
        for(Account au : accounts) {
            System.out.println(au);
            System.out.println(au.getUser());
    	} 
    }
    

    2. 一对多查询

    (0)需求:

    ​ 查询所有用户信息及用户关联的账户信息。

    (1)分析:

    ​ 用户信息和他的账户信息为一对多关系,并且查询过程中如果用户没有账户信息,此时也要将用户信息查询出来,我们想到了用左外连接查询比较合适。

    (2)编写SQL语句:

    SELECT
    	u.*, acc.id, acc.uid, acc.money
    FROM
    	user u
    LEFT OUTER JOIN account acc ON u.id = acc.uid
    

    (3)在User 类中加入 List< Account >:

    public class User implements Serializable {
        private Integer id;
        private String username;
        private Date birthday;
        private String sex;
        private String address;
        private List<Account> accounts;
        public List<Account> getAccounts() {
        	return accounts; 
        }
        public void setAccounts(List<Account> accounts) {
        	this.accounts = accounts; 
        }
        public Integer getId() {
        	return id; 
        }
        public void setId(Integer id) {
        	this.id = id; 
        }
        public String getUsername() {
        	return username; 
        }
        public void setUsername(String username) {
        	this.username = username; 
        }
        public Date getBirthday() {
        	return birthday; 
        }
        public void setBirthday(Date birthday) {
        	this.birthday = birthday; 
        }
        public String getSex() {
        	return sex; 
        }
        public void setSex(String sex) {
        	this.sex = sex; 
        }
        public String getAddress() {
        	return address; 
        }
        public void setAddress(String address) {
        	this.address = address; 
        }
        @Override
        public String toString() {
        	return "User [id=" + id + ", username=" + username + ", birthday=" + birthday+ ", sex=" + sex + ", address="+ address + "]"; 
        } 
    }
    

    (4)持久层Dao接口:

    /**
    * 查询所有用户,同时获取出每个用户下的所有账户信息
    * @return
    */
    List<User> findAll();
    

    (5)映射配置文件:

    <?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.itheima.dao.IUserDao"> 
    
    	<resultMap type="user" id="userMap"> 
            <id column="id" property="id"></id> 
            <result column="username" property="username"/>
            <result column="address" property="address"/>
            <result column="sex" property="sex"/>
            <result column="birthday" property="birthday"/>
            <!-- collection 是用于建立一对多中集合属性的对应关系
                 ofType 用于指定集合元素的数据类型
            --> 
            <collection property="accounts" ofType="account"> 
            	<id column="aid" property="id"/>
                <result column="uid" property="uid"/>
                <result column="money" property="money"/>
    		</collection>
    	</resultMap>
    	
    	<!-- 配置查询所有操作 --> 
    	<select id="findAll" resultMap="userMap">
    		select u.*, a.id as aid , a.uid, a.money from user u left outer join account a on u.id = a.uid
    	</select>
    </mapper>
    

    ​ collection部分定义了用户关联的账户信息,表示关联查询结果集。

    ​ 属性 property 定义了关联查询的结果集存储在 User 对象的上哪个属性。

    ​ 属性 ofType 定义了关联查询的结果集中的对象类型,即List中的对象类型。

    (6)测试:

    public class UserTest {
        private InputStream in ;
        private SqlSessionFactory factory;
        private SqlSession session;
        private IUserDao userDao;
    	@Test
    	public void testFindAll() {
            //6.执行操作
            List<User> users = userDao.findAll();
            for(User user : users) {
                System.out.println("-------每个用户的内容---------");
                System.out.println(user);
                System.out.println(user.getAccounts());
    		} 
    	}
        @Before//在测试方法执行之前执行
        public void init() throws Exception {
            //1.读取配置文件
            in = Resources.getResourceAsStream("SqlMapConfig.xml");
            //2.创建构建者对象
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            //3.创建 SqlSession 工厂对象
            factory = builder.build(in);
            //4.创建 SqlSession 对象
            session = factory.openSession();
            //5.创建 Dao 的代理对象
            userDao = session.getMapper(IUserDao.class);
        }
        @After//在测试方法执行完成之后执行
        public void destroy() throws Exception{
            session.commit();
            //7.释放资源
            session.close();
            in.close();
    	} 
    }
    

    四、MyBatis的延迟加载策略

    1. 概念

    延迟加载:就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载.

    好处:

    ​ 先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度快。

    坏处:

    ​ 因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时间,所以可能造成用户等待时间变长,造成用户体验下降。

    2. 需求

    ​ 查询账户(Account)信息并且关联查询用户(User)信息。先查询账户(Account)信息即可满足要求,当我们需要查询用户(User)信息时再查询用户(User)信息。对用户(User)信息的按需查询就是延迟加载。

    ​ 在使用MyBatis进行多表查询时,我们通过association、collection 实现一对一及一对多映射。association、collection 具备延迟加载功能。

    3. 使用 assocation 实现延迟加载(一对一)

    (0)需求:

    ​ 查询账户信息的同时关联查询用户信息。

    (1)账户的持久层Dao接口:

    public interface IAccountDao {
        /**
        * 查询所有账户,同时获取账户的所属用户名称以及他的地址信息
        * @return
        */
        List<Account> findAll();
    }
    

    (2)账户的持久层映射文件:

    <?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.itheima.dao.IAccountDao">
    	<!-- 建立对应关系 --> 
    	<resultMap type="account" id="accountMap"> 
    		<id column="aid" property="id"/>
    		<result column="uid" property="uid"/>
    		<result column="money" property="money"/>
    		<!--
    			select: 填写我们要调用的 select 映射的 id 
    			column: 填写我们要传递给 select 映射的参数 
    		--> 
    		<association property="user" javaType="user"
    			select="com.itheima.dao.IUserDao.findById"
    			column="uid">
    		</association>
    	</resultMap> 
    	
    	<select id="findAll" resultMap="accountMap">
    		select * from account
    	</select>
    </mapper>
    

    (4)用户的持久层接口和映射文件:

    public interface IUserDao {
        /**
        * 根据 id 查询
        * @param userId
        * @return
        */
        User findById(Integer userId);
    }
    
    <?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.itheima.dao.IUserDao">
    	
    	<!-- 根据 id 查询 --> 
    	<select id="findById" resultType="user" parameterType="int" >
    		select * from user where id = #{uid}
    	</select>
    </mapper>
    

    (5)开启 Mybatis 的延迟加载策略:

    ​ 我们需要在 MyBatis 的配置文件 SqlMapConfig.xml 文件中添加延迟加载的配置。

    <!-- 开启延迟加载的支持 -->
    <settings> 
    	<setting name="lazyLoadingEnabled" value="true"/>
    	<setting name="aggressiveLazyLoading" value="false"/>
    </settings>
    

    (6)编写测试只查账户信息不查用户信息:

    public class AccountTest {
        private InputStream in ;
        private SqlSessionFactory factory;
        private SqlSession session;
        private IAccountDao accountDao;
        @Test
        public void testFindAll() {
            //6.执行操作
            List<Account> accounts = accountDao.findAll();
        }
        @Before//在测试方法执行之前执行
        public void init()throws Exception {
            //1.读取配置文件
            in = Resources.getResourceAsStream("SqlMapConfig.xml");
            //2.创建构建者对象
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            //3.创建 SqlSession 工厂对象
            factory = builder.build(in);
            //4.创建 SqlSession 对象
            session = factory.openSession();
            //5.创建 Dao 的代理对象
            accountDao = session.getMapper(IAccountDao.class);
        }
        @After//在测试方法执行完成之后执行
        public void destroy() throws Exception{
            //7.释放资源
            session.close();
            in.close();
    	} 
    }
    

    4. 使用 collection 实现延迟加载(一对多)

    ​ 同样我们也可以在一对多关系配置的< collection >标签中配置延迟加载策略。< collection >结点中也有 select 属性和 column 属性。

    (0)需求:

    ​ 完成加载用户对象时,查询该用户所拥有的账户信息。

    (1)在 User 实体类中加入 List< Account >属性:

    public class User implements Serializable {
        private Integer id;
        private String username;
        private Date birthday;
        private String sex;
        private String address;
        private List<Account> accounts;
        public List<Account> getAccounts() {
        	return accounts;
        }
        public void setAccounts(List<Account> accounts) {
        	this.accounts = accounts;
        }
        public Integer getId() {
        	return id; 
        }
        public void setId(Integer id) {
        	this.id = id; 
        }
        public String getUsername() {
        	return username; 
        }
        public void setUsername(String username) {
        	this.username = username; 
        }
        public Date getBirthday() {
        	return birthday; 
        }
        public void setBirthday(Date birthday) {
        	this.birthday = birthday; 
        }
        public String getSex() {
        	return sex; 
        }
        public void setSex(String sex) {
        	this.sex = sex; 
        }
        public String getAddress() {
        	return address; 
        }
        public void setAddress(String address) {
        	this.address = address; 
        }
        @Override
        public String toString() {
        	return "User [id=" + id + ", username=" + username + ", birthday=" + birthday
        	+ ", sex=" + sex + ", address="
    		+ address + "]"; 
    	} 
    }
    

    (2)编写用户和账户持久层接口的方法:

    /**
    * 查询所有用户,同时获取出每个用户下的所有账户信息
    * @return
    */
    List<User> findAll();
    
    /**
    * 根据用户 id 查询账户信息
    * @param uid
    * @return
    */
    List<Account> findByUid(Integer uid);
    

    (3)用户的持久层映射文件:

    <resultMap type="user" id="userMap"> 
        <id column="id" property="id"></id> 
        <result column="username" property="username"/>
        <result column="address" property="address"/>
        <result column="sex" property="sex"/>
        <result column="birthday" property="birthday"/>
        <!-- collection 是用于建立一对多中集合属性的对应关系
            ofType 用于指定集合元素的数据类型
            select 是用于指定查询账户的唯一标识(账户的 dao 全限定类名加上方法名称)
            column 是用于指定使用哪个字段的值作为条件查询
    	--> 
    	<collection property="accounts" ofType="account"
    		select="com.itheima.dao.IAccountDao.findByUid"
    		column="id">
    	</collection>
    </resultMap>
    
    <!-- 配置查询所有操作 --> 
    <select id="findAll" resultMap="userMap">
    	select * from user
    </select>
    

    (4)账户的持久层映射文件:

    <!-- 根据用户 id 查询账户信息 --> 
    <select id="findByUid" resultType="account" parameterType="int">
    	select * from account where uid = #{uid}
    </select>
    

    (5)测试只加载用户信息:

    public class UserTest {
        private InputStream in ;
        private SqlSessionFactory factory;
        private SqlSession session;
        private IUserDao userDao;
        @Test
        public void testFindAll() {
            //6.执行操作
            List<User> users = userDao.findAll();
        }
        @Before//在测试方法执行之前执行
        public void init() throws Exception {
            //1.读取配置文件
            in = Resources.getResourceAsStream("SqlMapConfig.xml");
            //2.创建构建者对象
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            //3.创建 SqlSession 工厂对象
            factory = builder.build(in);
            //4.创建 SqlSession 对象
            session = factory.openSession();
            //5.创建 Dao 的代理对象
            userDao = session.getMapper(IUserDao.class);
        }
        @After//在测试方法执行完成之后执行
        public void destroy() throws Exception{
            session.commit();
            //7.释放资源
            session.close();
            in.close();
        } 
    }
    

    五、MyBatis的缓存

    ​ 像大多数的持久层框架一样,MyBatis 也提供了缓存策略,通过缓存策略来减少数据库的查询次数,从而提高性能。MyBatis 中的缓存分为一级缓存和二级缓存。

    1. MyBatis的一级缓存

    ​ 一级缓存是 SqlSession 范围的缓存,当调用 SqlSession 的修改,添加,删除,commit(),close()等方法时,就会清空一级缓存。

    ​ 第一次发起查询用户 id 为 1 的用户信息,先去找缓存中是否有 id 为 1 的用户信息,如果没有,从数据库查询用户信息,得到用户信息,将用户信息存储到一级缓存中。

    ​ 第二次发起查询用户 id 为 1 的用户信息,先去找缓存中是否有 id 为 1 的用户信息,缓存中有,直接从缓存中获取用户信息。

    ​ 如果 SqlSession 去执行 commit 操作(执行插入、更新、删除),则清空 SqlSession 中的一级缓存。这样做的目的为了让缓存中存储的都是最新的信息,避免脏读。

    2. MyBatis的二级缓存

    ​ 二级缓存是 mapper 映射级别的缓存,多个 SqlSession 去操作同一个 Mapper 映射的 SQL 语句,多个SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession 的。

    ​ sqlSession1 去查询用户信息,查询到用户信息会将查询数据存储到二级缓存中。

    ​ sqlSession2 去查询与 sqlSession1 相同的用户信息,首先会去缓存中找是否存在数据,如果存在则直接从缓存中取出数据。

    ​ 如果 sqlSession3 去执行相同 mapper 映射下的 SQL,执行 commit 提交,将会清空该 mapper 映射下的二级缓存区域的数据。

  • 相关阅读:
    统计学六:逻辑回归
    数据分析五:因子分析
    统计学四:聚类分析
    统计学三:线性回归
    统计学二:假设检验与参数估计
    统计学一:描述统计
    数据分析十:高价值用户识别
    数据分析九:互联网征信中的信用评分模型(用户APP使用行为分析)
    数据分析八:互联网征信中的信用评分模型(刷卡行为分析)
    数据分析七:数据治理
  • 原文地址:https://www.cnblogs.com/jiajun107/p/13435991.html
Copyright © 2011-2022 走看看