Mybatis基础概念与高级应用小结

目录
  • Mybatis基础回顾与高级应用
    • 引入依赖
    • jdbc.properties
    • sqlMapConfig.xml
  • 案例一-查询用户
    • 案例二-添加用户
    • 案例三-编辑用户
    • 案例四-删除用户
    • 传统开发方式
    • 代理开发方式(使用JDK动态代理产生代理对象,由代理对象执行并且操作)
    • 动态sql语句 if标签
  • Mybatis复杂映射
    • 一对一
    • 一对多
    • 多对多
  • Mybatis注解开发
    • Mybatis注解实现复杂映射开发
  • Mybatis缓存
    • 基础概念
    • 一级缓存
      • 返回结果为 true ;测试一级缓存是默认开启的
      • 返回结果为 false
    • 二级缓存
      • 如何使用二级缓存
      • 返回结果为 false

Mybatis基础回顾与高级应用

数据库:mysql5.7

jdk:15

引入依赖

<!--引入依赖-->
    <dependencies>
        <!--mybatis坐标-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.5</version>
        </dependency>
        <!--mysql驱动坐标-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
            <scope>runtime</scope>
        </dependency>
        <!--单元测试坐标-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
        </dependency>
    </dependencies>

User实体

@Data
public class User {
    private Integer id;
    private String username;
}

jdbc.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1/zdy_mybatis
jdbc.username=root
jdbc.password=root

sqlMapConfig.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--加载外部的properties文件-->
    <properties resource="jdbc.properties"></properties>
​
    <!--给实体类的全限定类名给别名-->
    <typeAliases>
        <!--给单独的实体起别名-->
     <!--   <typeAlias type="com.yun.pojo.User" alias="user"></typeAlias>-->
        <!--批量起别名:该包下所有的类的本身的类名:别名还不区分大小写-->
        <package name="com.yun.pojo"/>
    </typeAliases>
​
    <!--environments:运行环境-->
    <environments default="development">
        <environment id="development">
            <!--当前事务交由JDBC进行管理-->
            <transactionManager type="JDBC"></transactionManager>
            <!--当前使用mybatis提供的连接池-->
            <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>
        <mapper resource="UserMapper.xml"></mapper>
    </mappers>
</configuration>

案例一-查询用户

UserMapper.xml

<mapper namespace="user">
    <!--select-->
    <select id="findAll" resultType="com.yun.pojo.User">
        select * from user
    </select>
</mapper>
@Test
    public void test1() throws IOException {
        //1.Resources工具类,配置文件的加载,把配置文件加载成字节输入流
        InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml");
        //2.解析了配置文件,并创建了sqlSessionFactory工厂
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //3.生产sqlSession
        // 默认开启一个事务,但是该事务不会自动提交
        //在进行增删改操作时,要手动提交事务
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //4.sqlSession调用方法:查询所有selectList  查询单个:selectOne 添加:insert  修改:update 删除:delete
        List<User> users = sqlSession.selectList("user.findAll");
        users.forEach(item ->{
            System.out.println(item);
        });
        sqlSession.close();
​
    }

输出结果

User(id=1, username=Tom)
User(id=2, username=Jerry)

案例二-添加用户

UserMapper.xml

<!--parameterType:参数类型-->
<insert id="saveUser" parameterType="com.yun.pojo.User">
        insert into user Values (#{id},#{username})
</insert>
@Test
    public void test2() throws IOException {
        InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        User user = new User();
        user.setId(3);
        user.setUsername("jack");
        sqlSession.insert("user.saveUser",user);
        sqlSession.commit();
        sqlSession.close();
    }

数据库结果:

案例三-编辑用户

UserMapper.xml

<update id="updateUser" parameterType="com.yun.pojo.User">
        update user set username = #{username} where id = #{id}
</update>
@Test
    public void test3() throws IOException {
        InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        User user = new User();
        user.setId(3);
        user.setUsername("rose");
        sqlSession.update("user.updateUser",user);
        sqlSession.commit();
        sqlSession.close();
    }

数据库结果:

案例四-删除用户

UserMapper.xml

<delete id="deleteUser" parameterType="java.lang.Integer">
        delete from user where id =#{id}
</delete>
 @Test
    public void test4() throws IOException {
        InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
​
        User user = new User();
        user.setId(3);
        sqlSession.delete("user.deleteUser",3);
        sqlSession.commit();
​
        sqlSession.close();
​
    }

数据库结果:

传统开发方式

public interface IUserDao {
​
    //查询所有用户
    List<User> findAll() throws IOException;
}

UserDaoImpl

public class UserDaoImpl implements IUserDao {
​
    @Override
    public List<User> findAll() throws IOException {
        InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        List<User> users = sqlSession.selectList("user.findAll");
        sqlSession.close();
        return users;
    }
}
@Test
    public void test5() throws IOException {
        UserDaoImpl dao = new UserDaoImpl();
        List<User> users = dao.findAll();
        System.out.println(users);
    }

打印结果:

[User(id=1, username=Tom), User(id=2, username=Jerry)]

代理开发方式(使用JDK动态代理产生代理对象,由代理对象执行并且操作)

Mapper接口开发需要遵行以下规范:

mapper.xml文件中的namespace与mapper接口的全限定名相同;
2. mapper接口方法名和mapper.xml中定义的每个statement的id相同
3. mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同
4. mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同

根据上述的规范修改UserMapper.xml

<mapper namespace="com.yun.dao.IUserDao">
​
    <!--select-->
    <select id="findAll" resultType="com.yun.pojo.User">
        select * from user
    </select>
</mapper>
public interface IUserDao {
​
    //查询所有用户
    List<User> findAll() throws IOException;
}
@Test
public void test6() throws IOException {
    InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
    SqlSession sqlSession = sqlSessionFactory.openSession();
​
    IUserDao mapper = sqlSession.getMapper(IUserDao.class);
    List<User> all = mapper.findAll();
    all.forEach(item ->{
        System.out.println(all);
    });
}

输出结果:

User(id=1, username=Tom)
User(id=2, username=Jerry)

动态sql语句 if标签

public interface IUserDao {
​
    //多条件组合查询:演示if
    public List<User> findByCondition(User user);
}
<!--抽取sql片段-->
<sql id="selectUser">
    select * from user
</sql>
​
<!--多条件组合查询:演示if-->
<select id="findByCondition" parameterType="user" resultType="user">
   <include refid="selectUser"></include>
   <where>
       <if test="id !=null">
           and id = #{id}
       </if>
       <if test="username !=null">
           and username = #{username}
       </if>
   </where>
</select>
@Test
    public void test7() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
​
        IUserDao mapper = sqlSession.getMapper(IUserDao.class);
​
        User user1 = new User();
        user1.setId(1);
        user1.setUsername("Tom");
​
        List<User> all = mapper.findByCondition(user1);
        for (User user : all) {
            System.out.println(user);
        }
    }

输出结果:

User(id=1, username=Tom)

动态sql语句 foreach标签

public interface IUserDao {
​
    //多值查询:演示foreach
    public List<User> findByIds(int[] ids);
}
<!--多值查询:演示foreach-->
<select id="findByIds" parameterType="list" resultType="user">
   <include refid="selectUser"></include>
   <where>
       <foreach collection="array" open="id in (" close=")" item="id" separator=",">
           #{id}
       </foreach>
   </where>
</select>
@Test
public void test8() throws IOException {
   InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
   SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
   SqlSession sqlSession = sqlSessionFactory.openSession();
​
   IUserDao mapper = sqlSession.getMapper(IUserDao.class);
​
   int[] arr = {1,2};
​
   List<User> all = mapper.findByIds(arr);
   for (User user : all) {
       System.out.println(user);
   }
}

输出结果:

User(id=1, username=Tom)
User(id=2, username=Jerry)

Mybatis复杂映射

一对一

User实体

@Data
public class User {
​
    private Integer id;
​
    private String username;
​
    //该用户所具有的订单信息
    private List<Order> orders;
​
    //该用户所具有的角色信息
    private List<Role> roles;
}

Order实体

@Data
public class Order {
​
    private Integer id;
​
    private String orderTime;
​
    private BigDecimal total;
​
    //表明该订单属于哪个用户
    private User user;
}

Role实体

@Data
public class Role {
​
    private Integer id;
​
    private String roleName;
}
public interface IOrderMapper {
​
    /**
     * 查询订单的同时还查询该订单所属的用户
     * @return
     */
    public List<Order> findOrderAndUser();
}
<resultMap id="orderMap" type="com.yun.pojo.Order">
    <result property="id" column="id"></result>
    <result property="orderTime" column="order_time"></result>
    <result property="total" column="total"></result>
​
    <association property="user" javaType="com.yun.pojo.User">
        <result property="id" column="uid"></result>
        <result property="username" column="username"></result>
    </association>
</resultMap>
​
<!--resultMap:手动来配置实体属性与表字段的映射关系-->
<select id="findOrderAndUser" resultMap="orderMap">
    select * from orders o,user u  where o.uid = u.id
</select>
@Test
public void test1() throws IOException {
    //1.Resources工具类,配置文件的加载,把配置文件加载成字节输入流
    InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml");
    //2.解析了配置文件,并创建了sqlSessionFactory工厂
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    //3.生产sqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession();
    IOrderMapper mapper = sqlSession.getMapper(IOrderMapper.class);
    List<Order> orderAndUser = mapper.findOrderAndUser();
    orderAndUser.forEach(order -> {
        System.out.println(order);
    });
}

运行结果:

Order(id=1, orderTime=2022-05-01, total=1000.00, user=User(id=1, username=Tom, orders=null, roles=null))
Order(id=2, orderTime=2022-05-10, total=2000.00, user=User(id=2, username=Jerry, orders=null, roles=null))
Order(id=3, orderTime=2022-05-20, total=3000.00, user=User(id=2, username=Jerry, orders=null, roles=null))

一对多

public interface IUserMapper {
​
    /**
     * 查询所有用户信息,同时查询出每个用户关联的订单信息
     * @return
     */
    public List<User> findAll();
}
<resultMap id="userMap" type="com.yun.pojo.User">
    <id property="id" column="id"></id>
    <result property="username" column="username"></result>
​
    <collection property="orders" ofType="com.yun.pojo.Order">
        <id property="id" column="oid"></id>
        <result property="orderTime" column="order_time"></result>
        <result property="total" column="total"></result>
    </collection>
</resultMap>
​
<!--resultMap:手动来配置实体属性与表字段的映射关系-->
<select id="findAll" resultMap="userMap">
    select u.*,o.id oid,o.order_time,o.total,o.uid from user u left join orders o on u.id = o.uid
</select>
@Test
    public void test2() throws IOException {
        //1.Resources工具类,配置文件的加载,把配置文件加载成字节输入流
        InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml");
        //2.解析了配置文件,并创建了sqlSessionFactory工厂
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //3.生产sqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        IUserMapper mapper = sqlSession.getMapper(IUserMapper.class);
        List<User> users = mapper.findAll();
        users.forEach(user -> {
            System.out.println(user.getUsername());
            System.out.println(user.getOrders());
        });
    }

运行结果:

Tom
[Order(id=1, orderTime=2022-05-01, total=1000.00, user=null)]
Jerry
[Order(id=2, orderTime=2022-05-10, total=2000.00, user=null), Order(id=3, orderTime=2022-05-20, total=3000.00, user=null)]

多对多

public interface IUserMapper {
​
    /**
     * 查询所有用户信息,同事查询出每个用户关联的角色信息
     * @return
     */
    public List<User> findUserAndRole();
}
<resultMap id="userAndRoleMap" type="com.yun.pojo.User">
    <result property="id" column="userId"></result>
    <result property="username" column="username"></result>
​
    <collection property="roles" ofType="com.yun.pojo.Role">
        <result property="id" column="roleId"></result>
        <result property="roleName" column="rolename"></result>
    </collection>
</resultMap>
​
<select id="findUserAndRole" resultMap="userAndRoleMap">
    SELECT * FROM USER u
    LEFT JOIN sys_user_role sur ON u.id = sur.user_id
    LEFT JOIN sys_role sr ON sur.role_id = sr.id
</select>
@Test
public void test3() throws IOException {
    //1.Resources工具类,配置文件的加载,把配置文件加载成字节输入流
    InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml");
    //2.解析了配置文件,并创建了sqlSessionFactory工厂
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    //3.生产sqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession();
    IUserMapper mapper = sqlSession.getMapper(IUserMapper.class);
    List<User> users = mapper.findUserAndRole();
    users.forEach(user -> {
        System.out.println(user.getUsername());
        System.out.println(user.getRoles());
    });
}

运行结果:

Tom
[Role(id=null, roleName=董事长), Role(id=null, roleName=经理)]
Jerry
[Role(id=null, roleName=董事长), Role(id=null, roleName=经理)]

Mybatis注解开发

Mybasits常用注解:
@Insert: 实现新增
@Update: 实现更新
@Delete: 实现删除
@Select: 实现查询
@Result: 实现结果集封装;他代替的是标签<resultMap>,该注解中可以使用单个@Result注解,也可以使用@Result集合,
         使用格式:@Results({@Result(),@Result()}) 或 @Results(@Result())
@Results: 可以与@Result一起使用,封装多个结果集
@One: 实现一对一结果集封装
@Many: 实现一对多结果集封装

测试案例

public interface IUserMapper {
​
    //添加用户
    @Insert("insert into user values(#{id},#{username})")
    public void addUser(User user);
​
    //更新用户
    @Update("update user set username = #{} where id = #{id}")
    public void updateUser(User user);
​
    //查询用户
    @Select("select * from user")
    public List<User> getAllUser();
​
    //删除用户
    @Delete("delete from user where id=#{id}")
    public void delUser(Integer id);
}
private IUserMapper mapper;
​
    @Before
    public void before() throws IOException {
        //1.Resources工具类,配置文件的加载,把配置文件加载成字节输入流
        InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml");
        //2.解析了配置文件,并创建了sqlSessionFactory工厂
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //3.生产sqlSession                                     true:事务自动提交
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        mapper = sqlSession.getMapper(IUserMapper.class);
    }
​
    @Test
    public void addUser(){
        User user = new User();
        user.setId(3);
        user.setUsername("jack");
        mapper.addUser(user);
    }
​
    @Test
    public void updateUser(){
        User user = new User();
        user.setId(3);
        user.setUsername("rose");
        mapper.updateUser(user);
    }
​
    @Test
    public void getAllUser(){
        List<User> userList = mapper.getAllUser();
        userList.forEach(item -> {
            System.out.println(item);
        });
    }
​
    @Test
    public void delUser(){
        mapper.delUser(3);
    }

运行结果:

Mybatis注解实现复杂映射开发

一对一

public interface IOrderMapper {
​
    /**
     * 查询订单的同时还查询该订单所属的用户
     * @return
     */
    @Results({
            @Result(property = "id",column = "id"),
            @Result(property = "orderTime",column = "order_time"),
            @Result(property = "total",column = "total"),
            @Result(property = "user",column = "uid",javaType = User.class,
                    one = @One(select = "com.yun.mapper.IUserMapper.getUserById")),
    })
    @Select("select * from orders")
    public List<Order> findOrderAndUser();
}
​
public interface IUserMapper {
    @Select("select * from user where id = #{id}")
    public User getUserById(Integer id);
}
@Test
    public void oneToOne(){
        List<Order> orderAndUser = orderMapper.findOrderAndUser();
        orderAndUser.forEach(item -> {
            System.out.println(item);
        });
    }

运行结果:

Order(id=1, orderTime=2022-05-01, total=1000.00, user=User(id=1, username=Tom, orders=null, roles=null))
Order(id=2, orderTime=2022-05-10, total=2000.00, user=User(id=2, username=Jerry, orders=null, roles=null))
Order(id=3, orderTime=2022-05-20, total=3000.00, user=User(id=2, username=Jerry, orders=null, roles=null))

一对多

public interface IUserMapper {
​
    /**
     * 查询所有用户信息,同时查询出每个用户关联的订单信息
     * @return
     */
    @Select("select * from user")
    @Results({
            @Result(property = "id",column = "id"),
            @Result(property = "username",column = "username"),
            @Result(property = "orders",column = "id",javaType = List.class,
                    many = @Many(select = "com.yun.mapper.IOrderMapper.getOrderByUid"))
    })
    public List<User> findAll();
}
​
public interface IOrderMapper {
    @Select("select * from orders where uid = #{uid}")
    public List<Order> getOrderByUid(Integer uid);
}
@Test
    public void oneToMore(){
        List<User> users = mapper.findAll();
        users.forEach(item -> {
            System.out.println(item);
        });
​
    }

运行结果:

User(id=1, username=Tom, orders=[Order(id=1, orderTime=null, total=1000.00, user=null)], roles=null)
User(id=2, username=Jerry, orders=[Order(id=2, orderTime=null, total=2000.00, user=null), Order(id=3, orderTime=null, total=3000.00, user=null)], roles=null)

多对多

public interface IUserMapper {

    /**
    * 查询所有用户信息,同事查询出每个用户关联的角色信息
    * @return
    */
    @Select("select * from user")
    @Results({
            @Result(property = "id",column = "id"),
            @Result(property = "username",column = "username"),
            @Result(property = "roles",column = "id",javaType = List.class,
                    many = @Many(select ="com.yun.mapper.IRoleMapper.getAll"))
    })
    public List<User> findUserAndRole();
}
​
public interface IRoleMapper {
​
    @Select("select * from sys_role sr,sys_user_role sur where sr.id = sur.role_id and sur.user_id = #{uid}")
    public List<Role> getAll(Integer uid);
}
@Test
public void moreToMore(){

    List<User> users = mapper.findUserAndRole();
    users.forEach(item -> {
        System.out.println(item);
    });
}

运行结果:

User(id=1, username=Tom, orders=null, roles=[Role(id=1, roleName=董事长), Role(id=2, roleName=经理)])
User(id=2, username=Jerry, orders=null, roles=[Role(id=1, roleName=董事长), Role(id=2, roleName=经理)])

Mybatis缓存

基础概念

缓存就是内存中的数据,常常来自对数据库查询结果的保存,使用缓存,我们可以避免频繁的与数据库进行交互,进而提高响应速度.

一级缓存是SqlSession,在操作数据库时需要构造sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据.不同的sqlSession之间互不影响.

二级缓存是mapper级别的缓存,多个sqlSession去操作同一个mapper的sql语句,多个sqlSession可以共用二级缓存,二级缓存是跨sqlSession的.

一级缓存

demo

public class CacheTest {
​
    private IUserMapper mapper;
    private SqlSession sqlSession;
​
    @Before
    public void before() throws IOException {
        //1.Resources工具类,配置文件的加载,把配置文件加载成字节输入流
        InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml");
        //2.解析了配置文件,并创建了sqlSessionFactory工厂
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //3.生产sqlSession                          true:事务自动提交
        sqlSession = sqlSessionFactory.openSession(true);
        mapper = sqlSession.getMapper(IUserMapper.class);
    }
​
    @Test
    public void test1() {
​
        //第一次查询id为1的用户
        User user1 = mapper.getUserById(1);
​
        //第二次查询id为1的用户
        User user2 = mapper.getUserById(1);
​
        System.out.println(user1 == user2);
    }
}

返回结果为 true ;测试一级缓存是默认开启的

结论:第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户,如果没有,则从数据库查询用户信息,得到用户信息并且将用户信息存储到一级缓存中,第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户,如果缓存中有,直接从缓存中获取用户信息;

现在我们变换一下上面的demo

public class CacheTest {
​
    private IUserMapper mapper;
    private SqlSession sqlSession;
​
    @Before
    public void before() throws IOException {
        //1.Resources工具类,配置文件的加载,把配置文件加载成字节输入流
        InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml");
        //2.解析了配置文件,并创建了sqlSessionFactory工厂
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //3.生产sqlSession                          true:事务自动提交
        sqlSession = sqlSessionFactory.openSession();
        mapper = sqlSession.getMapper(IUserMapper.class);
    }
​
    @Test
    public void test1() {
​
        //第一次查询id为1的用户
        User user1 = mapper.getUserById(1);
​
        User user = new User();
        user.setId(1);
        user.setUsername("Lucy");
        mapper.updateUser(user);
​
        sqlSession.commit();
​
        //第二次查询id为1的用户
        User user2 = mapper.getUserById(1);
​
        System.out.println(user1 == user2);
    }
}

返回结果为 false

结论:做增删改操作,并进行了事物的提交,就会刷新以及缓存;或者还可以通过 sqlSession.clearCache()清楚缓存;这样做的目的就是为了让缓存中存储的是最新的信息,避免脏读;

二级缓存

二级缓存的原理和一级缓存原理一样,第一次查询会将数据放入缓存中,然后第二次查询则会直接从缓存中获取,但是一级缓存是基于sqlSession的,而二级缓存是基于mapper文件的namespace,也就是说,多个sqlSession可以共享一个mapper中的二级缓存,并且如果两个mapper的namespace相同,即使是两个mapper,那么这两个mapper执行sql查询到的数据也将存在相同的二级缓存区域中.

如何使用二级缓存

首先在全局配置文件sqlMapconfig.xml文件加入如下代码

<settings>
        <setting name="cacheEnabled" value="true"/>
</settings>

注意,该配置需要放在properties标签下,具体顺序,可百度了解

其次,在xxxMapper.xml文件中开启缓存(如果当前操作时基于注解开发的话,使用注解@CacheNamespace)

<cache></cache>

demo2

public class CacheTest {
​
    private IUserMapper mapper;
    private SqlSession sqlSession;
    private SqlSessionFactory sqlSessionFactory;
​
    @Before
    public void before() throws IOException {
        //1.Resources工具类,配置文件的加载,把配置文件加载成字节输入流
        InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml");
        //2.解析了配置文件,并创建了sqlSessionFactory工厂
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //3.生产sqlSession
        sqlSession = sqlSessionFactory.openSession();
        mapper = sqlSession.getMapper(IUserMapper.class);
    }
​
    @Test
    public void test2() {
​
        SqlSession sqlSession1 = sqlSessionFactory.openSession();
        SqlSession sqlSession2 = sqlSessionFactory.openSession();
        SqlSession sqlSession3 = sqlSessionFactory.openSession();
​
        IUserMapper mapper1 = sqlSession1.getMapper(IUserMapper.class);
        IUserMapper mapper2 = sqlSession2.getMapper(IUserMapper.class);
        IUserMapper mapper3 = sqlSession3.getMapper(IUserMapper.class);
​
        User user1 = mapper1.getUserById(1);
        //清空一级缓存
        sqlSession1.close();
        User user2 = mapper2.getUserById(1);
​
        System.out.println(user1 == user2);
    }
}

运行结果为 false

结论:通过debug断点显示,实际上,第二次查询则会直接从缓存中获取用户信息了,不过二级缓存缓存的不是对象,而是缓存的对象中的数据,所以查询结果为false;

注意,二级缓存底层还是HashMap结构,所以 po类需要实现序列化接口 ;因为二级缓存数据存储介质多种多样,不一定只存在内存中,有可能存在硬盘中,如果我们要在取这个缓存的话,就需要反序列化了,所以mybatis中的pojo都去实现Serializable接口;

变换一下demo2

@Test
    public void test2() {
        SqlSession sqlSession1 = sqlSessionFactory.openSession();
        SqlSession sqlSession2 = sqlSessionFactory.openSession();
        SqlSession sqlSession3 = sqlSessionFactory.openSession();
        IUserMapper mapper1 = sqlSession1.getMapper(IUserMapper.class);
        IUserMapper mapper2 = sqlSession2.getMapper(IUserMapper.class);
        IUserMapper mapper3 = sqlSession3.getMapper(IUserMapper.class);
        User user1 = mapper1.getUserById(1);
        //清空一级缓存
        sqlSession1.close();
        User user = new User();
        user.setId(1);
        user.setUsername("Tom");
        mapper3.updateUser(user);
        sqlSession3.commit();
        User user2 = mapper2.getUserById(1);
        System.out.println(user1 == user2);
    }

返回结果为 false

结论:做增删改操作,并进行了事物的提交,就会刷新以及缓存;这样做的目的就是为了让缓存中存储的是最新的信息,避免脏读;

此外mybatis中还可以配置useCache和flushCache等配置项;

useCache

是用来设置是否禁用二级缓存的,在statement中设置useCache=false可以禁用当前select语句的二级缓存,即每次查询都会会发出sql去查询,默认情况是true,即该sql使用二级缓存,例如

<select id="findAll" useCache = "false" resultMap="userMap">
        select u.*,o.id oid,o.order_time,o.total,o.uid from user u left join orders o on u.id = o.uid
</select>

使用sql注解方式可以使用@Options(useCache = false)的方式

flushCache

在mapper的同一个namespace中,如果有其他的insert,update,delete操作数据后需要刷新缓存,如果不执行刷新缓存会出现脏读,设置statememt配置中的

flushCache = "true"属性,默认情况下为true,即刷新缓存,如果改成false则不会刷新,使用缓存时如果手动修改数据库表中的查询数据会出现脏读 例如

<select id="findAll" flushCache = "true" useCache = "false" resultMap="userMap">
        select u.*,o.id oid,o.order_time,o.total,o.uid from user u left join orders o on u.id = o.uid
</select>

一般下执行完commit操作都需要刷新缓存,flushCache=true表示刷新缓存,这样可以避免数据库脏读,所以我们不用设置,默认即可

至此,mybatis基础概念及应用回顾完成!

到此这篇关于Mybatis基础回顾与高级应用的文章就介绍到这了,更多相关Mybatis高级应用内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java Mybatis框架入门基础教程

    一.Mybatis介绍 MyBatis是一款一流的支持自定义SQL.存储过程和高级映射的持久化框架.MyBatis几乎消除了所有的JDBC代码,也基本不需要手工去 设置参数和获取检索结果.MyBatis能够使用简单的XML格式或者注解进行来配置,能够映射基本数据元素.Map接口和POJOs(普通java对象)到数据库中的记录. 二.MyBatis工作流程 (1)加载配置并初始化 触发条件:加载配置文件 配置来源于两个地方,一处是配置文件,一处是Java代码的注解,将SQL的配置信息加载成为一个个

  • Spring+SpringMVC+MyBatis深入学习及搭建(一)之MyBatis的基础知识

    1.对原生态jdbc程序中问题总结 1.1 jdbc程序 需求:使用jdbc查询mysql数据库中用户表的记录 statement:向数据库中发送一个sql语句 预编译statement:好处:提高数据库性能. 预编译statement向数据库中发送一个sql语句,数据库编译sql语句,并把编译的结果保存在数据库砖的缓存中.下次再发sql时,如果sql相同,则不会再编译,直接使用缓存中的. jdbc编程步骤: 1. 加载数据库驱动 2. 创建并获取数据库链接 3. 创建jdbc statemen

  • 零基础搭建boot+MybatisPlus的详细教程

    目录 1.准备工作 1.1 创建数据库表 1.2 创建boot项目 1.3 创建实体类(映射数据库表) 2.使用mybatisPlus(操作数据库) 2.1 添加mybatisPlus依赖 2.2 配置数据库信息 2.3 创建mapper接口 2.4 配置mapper扫描 2.5 test 3. 常用设置 3.1 设置表映射规则 3.2 主键生成策略(默认基于雪花算法) 3.3 全局设置 3.4 字段与列名的驼峰映射(默认开启) 3.5 日志设置 4.基操 4.1 插入 insert() 4.2

  • MyBatis框架零基础快速入门案例详解

    目录 一.创建数据库和表 二.创建maven工程 三.代码编写 1.编写Student实体类 2.编写DAO接口StudentDao 3.编写DAO接口Mapper映射文件StudentDao.xml. 4.创建MyBatis主配置文件 四.创建测试类进行测试 1.创建测试类MyBatisTest 2.配置日志功能 五.增删改操作 insert操作 MyBatis下载地址:https://github.com/mybatis/mybatis-3/releases 一.创建数据库和表 数据库名ss

  • Spring整合SpringMVC + Mybatis基础框架的配置文件详解

    前言 新建一个普通的Maven项目 基本目录结构 ├── src # │ ├── main # │ │ └── java # java代码目录 │ │ └── resources # 配置文件目录, 存放下面Spring配置文件 │ ├── test # 单元测试目录 ├── web # web目录 │ └── WEB-INF # web.xml 配置文件目录 1. Mybatis层编写 1.在 resources 目录下新建数据库配置文件 database.properties jdbc.dr

  • Mybatis基础概念与高级应用小结

    目录 Mybatis基础回顾与高级应用 引入依赖 jdbc.properties sqlMapConfig.xml 案例一-查询用户 案例二-添加用户 案例三-编辑用户 案例四-删除用户 传统开发方式 代理开发方式(使用JDK动态代理产生代理对象,由代理对象执行并且操作) 动态sql语句 if标签 Mybatis复杂映射 一对一 一对多 多对多 Mybatis注解开发 Mybatis注解实现复杂映射开发 Mybatis缓存 基础概念 一级缓存 返回结果为 true ;测试一级缓存是默认开启的 返

  • 你不知道的 TypeScript 高级类型(小结)

    前言 对于有 JavaScript 基础的同学来说,入门 TypeScript 其实很容易,只需要简单掌握其基础的类型系统就可以逐步将 JS 应用过渡到 TS 应用. // js const double = (num) => 2 * num // ts const double = (num: number): number => 2 * num 然而,当应用越来越复杂,我们很容易把一些变量设置为 any 类型,TypeScript 写着写着也就成了 AnyScript.为了让大家能更加深入

  • Python装饰器基础概念与用法详解

    本文实例讲述了Python装饰器基础概念与用法.分享给大家供大家参考,具体如下: 装饰器基础 前面快速介绍了装饰器的语法,在这里,我们将深入装饰器内部工作机制,更详细更系统地介绍装饰器的内容,并学习自己编写新的装饰器的更多高级语法. 什么是装饰器 装饰是为函数和类指定管理代码的一种方式.Python装饰器以两种形式呈现: [1]函数装饰器在函数定义的时候进行名称重绑定,提供一个逻辑层来管理函数和方法或随后对它们的调用. [2]类装饰器在类定义的时候进行名称重绑定,提供一个逻辑层来管理类,或管理随

  • MySQL系列之开篇 MySQL关系型数据库基础概念

    目录 一.基础概念 二.数据库管理技术的发展 三.关系型数据库(RDBMS)概念 四.RDBMS设计范式 一.基础概念 数据(Data)是描述事物的符号记录,是指利用物理符号记录下来的.可以鉴别的信息. 1.数据库(Database,DB)是指长期储存在计算机中的有组织的.可共享的数据集合.数据要按照一定的数据模型组织.描述和存储,具有较小的冗余度.较高的数据独立性,系统易于扩展,并可以被多个用户分享. 数据的三个基本特点: 永久存储 有组织 可共享 2.数据库管理系统(DBMS)是专门用于建立

  • C++基础概念讲述

    目录 1.C++相关网站推荐 2.C++和C的关系 3.C++特性说明 3.1与底层硬件紧密结合 3.2对象生命周期的精确控制 3.3Zero-Overhead Abstraction 首先,通过一张最新(2021.11)的编程语言排名图来了解常见的编程语言: 从图中可以看出,C++的排名相对于Python.Java.C来说并不突出,很大的原因是因为C++难度过大,也可以说是知识点太多,我们很难说能精通C++这门语言,只能说对它的部分了解,并能在工作中使用: 1.C++相关网站推荐 1.cppr

  • Cocos2d-x 3.x入门教程(一):基础概念

    前言 接触游戏开发时间不长,之前一直都是写Lua,写Lua肯定是没有什么发展的啦,至少你要会写的.写客户端,肯定要看看Cocos2d-x了.从今天起,正式开始Cocos2d-X的学习之旅. 之前一直都是做C++开发的,转过来看Cocos2d-x,从语言上来说,没有多少问题.对于我来说,Cocos2d-x就是一个类库,就类似于MFC.ATL和QT一样,就是一个游戏类库,而我就按照学习类库使用的方法去学习Cocos2d-x.这篇文章叫基础概念,但是还是从整体来说说Cocos2d-x这个类库的. 基础

  • mybatis 中 foreach collection的用法小结(三种)

    foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合. foreach元素的属性主要有 item,index,collection,open,separator,close. item表示集合中每一个元素进行迭代时的别名,     index指 定一个名字,用于表示在迭代过程中,每次迭代到的位置,     open表示该语句以什么开始,     separator表示在每次进行迭代之间以什么符号作为分隔 符,     close表示以什么结束. 在使用foreach的时候

  • Java线程安全基础概念解析

    Java线程安全初步了解.JAVA线程安全从总体上来说,是指Java对象在多线程运行环境下的一种特性,表现为常规(区别于特殊调用情况)情况下每次调用都能得到正确的逻辑结果.从本质上来说,将对象的方法行为加上了同步控制逻辑,而调用者无须做其他额外的同步控制就可以安全放心的使用对象. 1.线程安全的定义 当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那这个对象就是线程安

  • java语言注解基础概念详解

    1.RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃: 2.RetentionPolicy.CLASS:注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期: 3.RetentionPolicy.RUNTIME:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在: 这3个生命周期分别对应于:Java源文件(.java文件)--->.class文件--->内存中的字节码.

随机推荐