Mybatis(三)多表查询、注解开发、一对一、一对多、多对多查询、缓存(一级缓存、二级缓存)

mybatis注解的详解和开发(增、删、改、查以及一对一、一对多/多对一、多对多的关系联查) Results代替了标签< resultMap> 该注解中可以使用单个@Result注解,也可以使用@Result集合格式:@Results ({@Result () , @Result ()}) 或者@Result (@Result())id 是否是主键字段column 数据库中列的名property 需要装配的属性名one 需要使用 @One 注解 (@Result (one = @One) ()) 阅读详情

1.Mybatis多表查询

1.1 一对一查询

1.1.1 一对一查询的模型

MapperScannerConfigurer

  用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户

一对一查询的需求:查询一个订单,与此同时查询出该订单所属的用户

在这里插入图片描述

1.1.2一对一查询的语句

  对应的sql语句:select * from orders o,user u where o.uid=u.id;

查询的结果如下:

在这里插入图片描述

1.1.3 创建Order和User实体

public class Order {

    private int id;
    private Date ordertime;
    private double total;

    //代表当前订单从属于哪一个客户
    private User user;
}

public class User {
    
    private int id;
    private String username;
    private String password;
    private Date birthday;

}

1.1.4 创建OrderMapper接口

public interface OrderMapper {
    List<Order> findAll();
}

1.1.5 配置OrderMapper.xml

<mapper namespace="com.itheima.mapper.OrderMapper">
    <resultMap id="orderMap" type="com.itheima.domain.Order">
        <result column="uid" property="user.id"></result>
        <result column="username" property="user.username"></result>
        <result column="password" property="user.password"></result>
        <result column="birthday" property="user.birthday"></result>
    </resultMap>
    <select id="findAll" resultMap="orderMap">
        select * from orders o,user u where o.uid=u.id
    </select>
</mapper>

其中还可以配置如下:

<resultMap id="orderMap" type="com.itheima.domain.Order">
    <result property="id" column="id"></result>
    <result property="ordertime" column="ordertime"></result>
    <result property="total" column="total"></result>
    <association property="user" javaType="com.itheima.domain.User">
        <result column="uid" property="id"></result>
        <result column="username" property="username"></result>
        <result column="password" property="password"></result>
        <result column="birthday" property="birthday"></result>
    </association>
</resultMap>

1.1.6 测试结果

OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
List<Order> all = mapper.findAll();
for(Order order : all){
    System.out.println(order);
}

在这里插入图片描述

1.2 一对多查询

1.2.1 一对多查询的模型

  用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户

一对多查询的需求:查询一个用户,与此同时查询出该用户具有的订单

在这里插入图片描述

1.2.2 一对多查询的语句

对应的sql语句:select *,o.id oid from user u left join orders o on u.id=o.uid;

查询的结果如下:

在这里插入图片描述

1.2.3 修改User实体

public class Order {

    private int id;
    private Date ordertime;
    private double total;

    //代表当前订单从属于哪一个客户
    private User user;
}

public class User {
    
    private int id;
    private String username;
    private String password;
    private Date birthday;
    //代表当前用户具备哪些订单
    private List<Order> orderList;
}

1.2.4 创建UserMapper接口

public interface UserMapper {
    List<User> findAll();
}

1.2.5 配置UserMapper.xml

<?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.zy.mapper.UserMapper">
        <!--    sql片段的抽取-->

    <select id="findAll" resultType="com.zy.entity.User">
        select * from user
    </select>
    <delete id="delete" parameterType="int">
        delete from user where id=#{id}
    </delete>
    <update id="update" parameterType="com.zy.entity.User">
        update  user set value username=#{username},password=#{password}
    </update>
    <insert id="insert" parameterType="com.zy.entity.User">
        insert into  user(username,password) value {#{username},#{password}}
    </insert>
    <select id="findByCollection" parameterType="user" resultType="user">
        selcet * from user
        <where>
        <if test="id!=0">
          and  id=#{id}
        </if>
        <if test="username!=null">
            and username =#{username}
        </if>
        <if test="password!=null">
            and password =#{password}
        </if>
        </where>
    </select>
    <select id="findByIds" resultType="user" parameterType="list">
        select * from user
        <where>
            <foreach collection="list" open="id in(" close=")" item="id" separator=",">
                #{id}
            </foreach>
        </where>
    </select>
    <insert id="insertOne" parameterType="user" >
        insert  into user (id,username,password,birthday) value {#{id},#{username},#{password},#{birthday}}
    </insert>
    <resultMap id="userMap" type="user">
        <id column="id" property="uid"/>
        <result column="username" property="username"/>
        <result column="password" property="password"/>
        <result column="birthday" property="birthday"/>
        <collection property="orders " column="uid" ofType="order" select="selectById" >
            <id column="oid" property="oid"/>
            <result column="ordertime" property="ordertime"/>
            <result column="total" property="total"/>
        </collection>
    </resultMap>
    <select id="findAll1" resultMap="userMap">
        select * from user u ,orders o where u.id = o.uid
    </select>
    <select id="selectById" parameterType="int" resultType="order">
        select * from orders where uid =#{uid}
    </select>


</mapper>

1.2.6 测试结果

UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> all = mapper.findAll();
for(User user : all){
    System.out.println(user.getUsername());
    List<Order> orderList = user.getOrderList();
    for(Order order : orderList){
        System.out.println(order);
    }
    System.out.println("----------------------------------");
}

在这里插入图片描述

1.3 多对多查询

1.3.1 多对多查询的模型

  用户表和角色表的关系为,一个用户有多个角色,一个角色被多个用户使用

多对多查询的需求:查询用户同时查询出该用户的所有角色

在这里插入图片描述

1.3.2 多对多查询的语句

  对应的sql语句:select u.,r.,r.id rid from user u left join user_role ur on u.id=ur.user_id

inner join role r on ur.role_id=r.id;

查询的结果如下:

在这里插入图片描述

1.3.3 创建Role实体,修改User实体

public class User {
    private int id;
    private String username;
    private String password;
    private Date birthday;
    //代表当前用户具备哪些订单
    private List<Order> orderList;
    //代表当前用户具备哪些角色
    private List<Role> roleList;
}

public class Role {

    private int id;
    private String rolename;

}

1.3.4 添加UserMapper接口方法

List<User> findAllUserAndRole();

1.3.5 配置UserMapper.xml

   <resultMap id="roleMap" type="user">
        <id column="uid" property="uid"/>
        <result column="username" property="username"/>
        <result column="password" property="password"/>
        <result column="birthday" property="birthday"/>
        <collection property="roles" ofType="role">
            <id column="rid" property="rid"/>
            <result column="roleName" property="roleName"/>
            <result column="roleDes" property="roleDes"/>
        </collection>
    </resultMap>
    <select id="findAllRole" resultMap="roleMap">
        select  * from `user` u,role_user ur ,role r where u.uid=ur.uid and ur.rid = r.rid
    </select>

1.3.6 测试结果

UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> all = mapper.findAllUserAndRole();
for(User user : all){
    System.out.println(user.getUsername());
    List<Role> roleList = user.getRoleList();
    for(Role role : roleList){
        System.out.println(role);
    }
    System.out.println("----------------------------------");
}

在这里插入图片描述

1.4 知识小结

MyBatis多表配置方式:

一对一配置:使用<resultMap >做配置

一对多配置:使用<resultMap>+<collection>做配置

多对多配置:使用<resultMap>+<collection>做配置

2.Mybatis的注解开发

2.1 MyBatis的常用注解

  这几年来注解开发越来越流行,Mybatis也可以使用注解开发方式,这样我们就可以减少编写Mapper

映射文件了。我们先围绕一些基本的CRUD来学习,再学习复杂映射多表操作。

@Insert:实现新增

@Update:实现更新

@Delete:实现删除

@Select:实现查询

@Result:实现结果集封装

@Results:可以与@Result 一起使用,封装多个结果集

@One:实现一对一结果集封装

@Many:实现一对多结果集封装

2.2 MyBatis的增删改查

我们完成简单的user表的增删改查的操作

private UserMapper userMapper;

@Before
public void before() throws IOException {
    InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
    SqlSessionFactory sqlSessionFactory = new 
                 SqlSessionFactoryBuilder().build(resourceAsStream);
    SqlSession sqlSession = sqlSessionFactory.openSession(true);
    userMapper = sqlSession.getMapper(UserMapper.class);
}

@Test
public void testAdd() {
    User user = new User();
    user.setUsername("测试数据");
    user.setPassword("123");
    user.setBirthday(new Date());
    userMapper.add(user);
}
@Test
public void testUpdate() throws IOException {
    User user = new User();
    user.setId(16);
    user.setUsername("测试数据修改");
    user.setPassword("abc");
    user.setBirthday(new Date());
    userMapper.update(user);
}

@Test
public void testDelete() throws IOException {
    userMapper.delete(16);
}
@Test
public void testFindById() throws IOException {
    User user = userMapper.findById(1);
    System.out.println(user);
}
@Test
public void testFindAll() throws IOException {
    List<User> all = userMapper.findAll();
    for(User user : all){
        System.out.println(user);
    }
}

  修改MyBatis的核心配置文件,我们使用了注解替代的映射文件,所以我们只需要加载使用了注解的Mapper接口即可

<mappers>
    <!--扫描使用注解的类-->
    <mapper class="com.zy.mapper.UserMapper"></mapper>
</mappers>

或者指定扫描包含映射关系的接口所在的包也可以

<mappers>
    <!--扫描使用注解的类所在的包-->
    <package name="com.zy.mapper"></package>
</mappers>

简单的注解映射开发

public interface UserMapper {
    @Insert(" insert into user values (#{uid},#{username},#{password},#{birthday})")
    void saveUser(User user);

    @Select("select * from user where uid=#{uid}")
    User findUserById(int id);

    @Delete("delete from user  where uid=#{uid}")
    int deleteById(int id);

    @Select("select * from user")
    List<User> findAll();

    @Update("update user set username=#{username},password=#{password},birthday=#{birthday} where uid=#{uid}")
    int update(User user);
}

2.3 MyBatis的注解实现复杂映射开发

  实现复杂关系映射之前我们可以在映射文件中通过配置来实现,使用注解开发后,我们可以使用@Results注解,@Result注解,@One注解,@Many注解组合完成复杂关系的配置

在这里插入图片描述

在这里插入图片描述

2.4 一对一查询

2.4.1 一对一查询的模型

  用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户

一对一查询的需求:查询一个订单,与此同时查询出该订单所属的用户

在这里插入图片描述

2.4.2 一对一查询的语句

对应的sql语句:

select * from orders;

select * from user where id=查询出订单的uid;

查询的结果如下:

在这里插入图片描述

2.4.3 创建Order和User实体

public class Order {

    private Integer id;
    private Date ordertime;
    private Integer total;

    //代表当前订单从属于哪一个客户
    private User user;
}

public class User {
    
    private int id;
    private String username;
    private String password;
    private Date birthday;

}

2.4.4 创建OrderMapper接口

public interface OrderMapper {
    List<Order> findAll();
}

OrderMapper

<?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.zy.mapper.OrderMapper">
<!--    手动指定字段与实体属性的映射关系-->
    <resultMap id="selectOrder" type="order">
        <id column="oid" property="oid"/>
        <result property="user.username" column="username"/>
        <result property="user.password" column="password"/>
        <result property="user.birthday" column="birthday"/>
        <result property="user.uid" column="uid"/>
    </resultMap>

    <select id="selectUserAndOrder" resultMap="selectOrder">
        select * from user u ,orders o where u.id =o.oid
    </select>
</mapper>

测试

public static void main(String[] args) throws IOException {
        InputStream stream = Resources.getResourceAsStream("MybatisConfig.xml");

        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(stream);
        SqlSession session = sessionFactory.openSession();

        OrderMapper orderMapper = session.getMapper(OrderMapper.class);
        List<Order> orders = orderMapper.selectUserAndOrder();
        for (Order order : orders) {
            System.out.println(order);
        }
        session.close();
    }

查询出来的字段就会被封装到user对象中打印出来
在这里插入图片描述

2.4.5 使用注解配置Mapper

public interface OrderMapper {

    @Select("select * from orders o , `user` u where o.uid=u.uid")
    @Results({
            @Result(column = "oid", property = "oid"),
            @Result(column = "ordertime", property = "ordertime"),
            @Result(column = "total", property = "total"),
            @Result(column = "uid", property = "user.uid"),
            @Result(column = "username", property = "user.username"),
            @Result(column = "password", property = "user.password"),
            @Result(column = "birthday", property = "user.birthday")
    }
    )
    //一对一查询的第二中写法类似于
    public List<Order> findAll1();

    @Select("select * from orders ")
    @Results({
            @Result(column = "oid", property = "oid"),
            @Result(column = "ordertime", property = "ordertime"),
            @Result(column = "total", property = "total"),
            @Result(
                    property = "user",//要封装的属性名称
                    column = "uid",
                    javaType = User.class,//要封装的实体类型
                    one = @One(select = "com.zy.mapper.UserMapper.findUserById")
            )
    }
    )
    public List<Order> findAll();

    @Select("select * from orders where uid=#{uid}")
    public List<Order> findUsers(int uid);


}

public interface UserMapper {

    @Select("select * from user where id=#{id}")
    User findById(int id);
    
}

2.4.6 测试结果

@Test
public void testSelectOrderAndUser() {
    List<Order> all = orderMapper.findAll();
    for(Order order : all){
        System.out.println(order);
    }
}

在这里插入图片描述

2.5 一对多查询

2.5.1 一对多查询的模型

  用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户

一对多查询的需求:查询一个用户,与此同时查询出该用户具有的订单

在这里插入图片描述

2.5.2 一对多查询的语句

对应的sql语句:

select * from user;

select * from orders where uid=查询出用户的id;

查询的结果如下:

在这里插入图片描述

2.5.3 修改User实体

public class Order {

    private int id;
    private Date ordertime;
    private double total;

    //代表当前订单从属于哪一个客户
    private User user;
}

public class User {
    
    private int id;
    private String username;
    private String password;
    private Date birthday;
    //代表当前用户具备哪些订单
    private List<Order> orderList;
}

2.5.4 创建UserMapper接口

List<User> findAllUserAndOrder();

2.5.5 使用注解配置Mapper

public interface UserMapper {
    @Insert(" insert into user values (#{uid},#{username},#{password},#{birthday})")
    void saveUser(User user);

    @Select("select * from user where uid=#{uid}")
    User findUserById(int id);

    @Delete("delete from user  where uid=#{uid}")
    int deleteById(int id);

    @Select("select * from user")
    List<User> findAll();

    @Update("update user set username=#{username},password=#{password},birthday=#{birthday} where uid=#{uid}")
    int update(User user);

    @Select("select * from user ")
    @Results({
            @Result(id = true,column = "uid",property = "uid"),//这个id表示这个是主键
            @Result(column = "username",property = "username"),
            @Result(column = "password",property = "password"),
            @Result(column = "birthday",property = "birthday"),
            @Result(
                    column = "uid",
                    property = "orders",
                    javaType = List.class,
                    many = @Many(select = "com.zy.mapper.OrderMapper.findUsers")

            )
    })
    public List<User> findUserAndOrder();

    @Select("select * from `user` ")
    @Results({
            @Result(id = true,column = "uid",property = "uid"),
            @Result(column = "username",property = "username"),
            @Result(column = "password",property = "password"),
            @Result(column = "birthday",property = "birthday"),
            @Result(
                    property = "roles",
                    column = "uid",
                    javaType = List.class,
                    many = @Many(select = "com.zy.mapper.RoleMapper.findUsers")

            )
    })
    public List<User> findUserAndRole();
}

2.5.6 测试结果

List<User> all = userMapper.findAllUserAndOrder();
for(User user : all){
    System.out.println(user.getUsername());
    List<Order> orderList = user.getOrderList();
    for(Order order : orderList){
        System.out.println(order);
    }
    System.out.println("-----------------------------");
}

在这里插入图片描述

2.6 多对多查询

2.6.1 多对多查询的模型

  用户表和角色表的关系为,一个用户有多个角色,一个角色被多个用户使用

多对多查询的需求:查询用户同时查询出该用户的所有角色

在这里插入图片描述

2.6.2 多对多查询的语句

对应的sql语句:

select * from user;

select * from role r,user_role ur where r.id=ur.role_id and ur.user_id=用户的id

查询的结果如下:

在这里插入图片描述

2.6.3 创建Role实体,修改User实体

public class User {
    private int id;
    private String username;
    private String password;
    private Date birthday;
    //代表当前用户具备哪些订单
    private List<Order> orderList;
    //代表当前用户具备哪些角色
    private List<Role> roleList;
}

public class Role {

    private int id;
    private String rolename;

}

2.6.4 添加UserMapper接口方法

List<User> findAllUserAndRole();

2.6.5 使用注解配置Mapper

public interface UserMapper {
   @Select("select * from `user` ")
    @Results({
            @Result(id = true,column = "uid",property = "uid"),
            @Result(column = "username",property = "username"),
            @Result(column = "password",property = "password"),
            @Result(column = "birthday",property = "birthday"),
            @Result(
                    property = "roles",
                    column = "uid",
                    javaType = List.class,
                    many = @Many(select = "com.zy.mapper.RoleMapper.findUsers")

            )
    })
    public List<User> findUserAndRole();



public interface RoleMapper {
@Select("select * from role where rid=#{uid}")
    public List<Role> findUsers(int uid);
}

2.6.6 测试结果

UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> all = mapper.findAllUserAndRole();
for(User user : all){
    System.out.println(user.getUsername());
    List<Role> roleList = user.getRoleList();
    for(Role role : roleList){
        System.out.println(role);
    }
    System.out.println("----------------------------------");
}

在这里插入图片描述

3.mybatis的缓存

MyBatis 缓存详解

  缓存是一般的ORM 框架都会提供的功能,目的就是提升查询的效率和减少数据库的压力。跟Hibernate 一样,MyBatis 也有一级缓存和二级缓存,并且预留了集成第三方缓存的接口。

缓存体系结构:

在这里插入图片描述

  MyBatis 跟缓存相关的类都在cache 包里面,其中有一个Cache 接口,只有一个默认的实现类 PerpetualCache,它是用HashMap 实现的。我们可以通过 以下类找到这个缓存

DefaultSqlSession

   -> BaseExecutor

     -> PerpetualCache localCache

       ->private Map<Object, Object> cache = new HashMap();

   除此之外,还有很多的装饰器,通过这些装饰器可以额外实现很多的功能:回收策略、日志记录、定时刷新等等。但是无论怎么装饰,经过多少层装饰,最后使用的还是基本的实现类(默认PerpetualCache)。可以通过 CachingExecutor 类 Debug 去查看。
在这里插入图片描述

   所有的缓存实现类总体上可分为三类:基本缓存、淘汰算法缓存、装饰器缓存。
在这里插入图片描述

一级缓存

  同一个 SqlSession 对象, 在参数和 SQL 完全一样的情况先, 只执行一次 SQL 语句(如果缓存没有过期)

  一级缓存也叫本地缓存,MyBatis 的一级缓存是在会话(SqlSession)层面进行缓存的。MyBatis 的一级缓存是默认开启的,不需要任何的配置。首先我们必须去弄清楚一个问题,在MyBatis 执行的流程里面,涉及到这么多的对象,那么缓存PerpetualCache 应该放在哪个对象里面去维护?如果要在同一个会话里面共享一级缓存,这个对象肯定是在SqlSession 里面创建的,作为SqlSession 的一个属性。

   DefaultSqlSession 里面只有两个属性,Configuration 是全局的,所以缓存只可能放在Executor 里面维护—SimpleExecutor/ReuseExecutor/BatchExecutor 的父类BaseExecutor 的构造函数中持有PerpetualCache。在同一个会话里面,多次执行相同的SQL 语句,会直接从内存取到缓存的结果,不会再发送SQL 到数据库。但是不同的会话里面,即使执行的SQL 一模一样(通过一个Mapper 的同一个方法的相同参数调用),也不能使用到一级缓存。

   每当我们使用MyBatis开启一次和数据库的会话,MyBatis会创建出一个SqlSession对象表示一次数据库会话。

   在对数据库的一次会话中,我们有可能会反复地执行完全相同的查询语句,如果不采取一些措施的话,每一次查询都会查询一次数据库,而我们在极短的时间内做了完全相同的查询,那么它们的结果极有可能完全相同,由于查询一次数据库的代价很大,这有可能造成很大的资源浪费。

   为了解决这一问题,减少资源的浪费,MyBatis会在表示会话的SqlSession对象中建立一个简单的缓存,将每次查询到的结果结果缓存起来,当下次查询的时候,如果判断先前有个完全一样的查询,会直接从缓存中直接将结果取出,返回给用户,不需要再进行一次数据库查询了。

   如下图所示,MyBatis会在一次会话的表示----一个SqlSession对象中创建一个本地缓存(local cache),对于每一次查询,都会尝试根据查询的条件去本地缓存中查找是否在缓存中,如果在缓存中,就直接从缓存中取出,然后返回给用户;否则,从数据库读取数据,将查询结果存入缓存并返回给用户。
在这里插入图片描述

刷新缓存

  刷新缓存是清空这个 SqlSession 的所有缓存, 不单单是某个键。

@Test
public void sameSqlSessionNoCache() {
    SqlSession sqlSession = null;
    try {
        sqlSession = sqlSessionFactory.openSession();

        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
        // 执行第一次查询
        Student student = studentMapper.selectByPrimaryKey(1);
        System.out.println("=============开始同一个 Sqlsession 的第二次查询============");
        // 同一个 sqlSession 进行第二次查询
        Student stu = studentMapper.selectByPrimaryKey(1);
        Assert.assertEquals(student, stu);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (sqlSession != null) {
            sqlSession.close();
        }
    }
}

在这里插入图片描述

  如果是以上, 没什么不同, 结果还是第二个不发 SQL 语句。

在此, 做一些修改, 在 StudentMapper.xml 中, 添加

flushCache=“true”

一级缓存的不足

   使用一级缓存的时候,因为缓存不能跨会话共享,不同的会话之间对于相同的数据可能有不一样的缓存。在有多个会话或者分布式环境下,会存在脏数据的问题。如果要解决这个问题,就要用到二级缓存。MyBatis 一级缓存(MyBaits 称其为 Local Cache)无法关闭,但是有两种级别可选:

  session 级别的缓存,在同一个 sqlSession 内,对同样的查询将不再查询数据库,直接从缓存中。
statement 级别的缓存,避坑: 为了避免这个问题,可以将一级缓存的级别设为 statement 级别的,这样每次查询结束都会清掉一级缓存。

一级缓存的生命周期

在这里插入图片描述

总结

  在同一个 SqlSession 中, Mybatis 会把执行的方法和参数通过算法生成缓存的键值, 将键值和结果存放在一个 Map 中, 如果后续的键值一样, 则直接从 Map 中获取数据;

  不同的 SqlSession 之间的缓存是相互隔离的;

  用一个 SqlSession, 可以通过配置使得在查询前清空缓存;

  任何的 UPDATE, INSERT, DELETE 语句都会清空缓存。

二级缓存

二级缓存:

  二级缓存是用来解决一级缓存不能跨会话共享的问题的,范围是namespace 级别的,可以被多个SqlSession 共享(只要是同一个接口里面的相同方法,都可以共享),生命周期和应用同步。如果你的MyBatis使用了二级缓存,并且你的Mapper和select语句也配置使用了二级缓存,那么在执行select查询的时候,MyBatis会先从二级缓存中取输入,其次才是一级缓存,即MyBatis查询数据的顺序是:二级缓存 —> 一级缓存 —> 数据库。

在这里插入图片描述

测试步骤

第一步:在核心配置文件中settings中设置缓存开启

在这里插入图片描述第二步
在需要设置缓存的select标签的属性中设置useache=true
在这里插入图片描述  测试: 查看控制台中sql语句执行的次数
   注意: 由于在更新时会刷新缓存, 因此需要注意使用场合:查询频率很高, 更新频率很低时使用, 即经常使用 select, 相对较少使用delete, insert, update。

  缓存是以 namespace 为单位的,不同 namespace 下的操作互不影响。但刷新缓存是刷新整个 namespace 的缓存, 也就是你 update 了一个, 则整个缓存都刷新了。

  最好在 「只有单表操作」 的表的 namespace 使用缓存, 而且对该表的操作都在这个 namespace 中。 否则可能会出现数据不一致的情况。

使用场景:

在这里插入图片描述

mybatis多表联查(一对一、一对多/多对一、多对多) 在开发过程中单表查询往往不能满足需求分析的很多功能,对于比较复杂业务来说,关联的表有几个,甚至是几十个并且表与表之间的关联相当复杂。为了能够实现复杂的功能业务,就必须进行多表查询,在mybatis中提供了多表查询映射标签,可以实现表之间的一对一、一对多、多对多关系的映射。 **注意:**大批代码正在向你靠近注意:测试代码块放最后运行出错可以看看在示例演练之前需要的准备:首先创建一个maven项目在pom.xml中配置文件 创建配置jdbc.properties 创建配置文件config.xml连接数据库和数 阅读详情

相关推荐

MyBatis使用注解式@One和@Many实现一对一、一对多关联查询

在MyBatis 3提供了新的基于注解的配置,下面将使用MyBatis的注解式@One和@Many实现一对一、一对多关联查询。 (1)创建SpringBoot项目,项目结构如下图: (2)添加pom.xml配置信息 在pom.xml配置文件中添加MyBatis、MySQL的JDBC数据库驱动。 <!-- MyBatis与SpringBoot整合依赖 --> <dependency> <groupId>org.mybatis.spring.boot&.

pan_junbiao的博客 2万+

mybatis 一对多查询

MyBatis 是一个优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。对于一对多查询,MyBatis 提供了很好的支持。 假设我们有一个 User 对象,每个 User 有多个 Order 对象,这是一个典型的一对多关系。

阿杰 3755

MyBatis通过注解实现多表联查:一对一/多对一关系

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 MyBatis通过注解实现多表联查:一对一/多对一关系前言一、MyBatis的常用注解说明二、使用步骤1.数据库配置关联表2.JavaBean类的属性2.Dao接口的注解2.1 一对一查询2.1 一对多查询补充 前言 [注意]使用MyBatis的注解的话,项目中不能出现相关dao接口的映射配置文件。 一、MyBatis的常用注解说明 @Insert:实现新增 @Update:实现更新 @Delete:实现删除 @Select:实现查询 @

weixin_42717117的博客 4064

mybatis查询子表

今天来记录一下 mybatis自动查询子表数据查询结果类如下: xml文件如下:

月月大王的博客 1989

mybatis一对多结果集,主表分页查询,子表条件查询

一对多查询嵌套查询: 主表查询过程中,再次调用一个查询,取查询子表数据嵌套结果集查询: 一次性查询主表关联出子表,通过结果集封装,将自己封装为一个集合,返回一个一对多的结果今天要说的是当: 做了一对多查询后,还要对多的子表,进行条件过滤,然后在反过来应用到主表上,继续分页查询~~丧心病狂的产品汪~~至此,一个一对多,然后用子表的过滤条件,作用到主表上的 分页…已经实现了~~

学海无涯,我用JAVA 3264

Mybatis一级缓存和二级缓存(带测试方法)

Mybatis一级缓存和二级缓存,详细介绍了一级缓存和二级缓存的区别,并通过测试方法来进行测试。

qq_53317005的博客 4634

Mybatis注解开发(超详细)

Mybatis注解开发mybatis的常用注解使用 Mybatis 注解实现基本 CRUD项目目录结构编写实体类使用注解方式开发持久层接口编写 SqlMapConfig.xml 配置文件编写测试代码使用注解实现复杂关系映射开发复杂关系映射的注解说明项目目录使用注解实现一对一复杂关系映射及立即加载添加 User 实体类及 Account 实体类添加账户的持久层接口并使用注解配置添加用户的持久层接口并使用注解配置测试一对一关联及立即加载使用注解实现一对多复杂关系映射及延迟加载User 实体类加入 List``编

『愚』的博客 5万+

MSPM0G3507+逐飞库:5分钟搞定KEIL环境配置与LED闪烁(附常见错误解决)

本文详细介绍了如何使用MSPM0G3507微控制器和逐飞库快速配置KEIL开发环境,并实现LED闪烁功能。从芯片支持包安装、逐飞库工程配置到烧录调试,提供了完整的步骤和常见错误解决方案,帮助开发者5分钟内完成环境搭建。

lambda的博客 1195

Mybatis学习(三):Mybatis注解开发、缓存使用和插件使用的深度分析

Mybatis学习(三):Mybatis注解开发、缓存使用和插件使用的深度分析讲解前言一、Mybatis传统XML配置开发1.1 一对一查询1.2 一对多查询1.3 多对多查询二、Mybatis注解开发2.1 Mybatis注解2.2 Mybatis的CRUD之注解开发2.3 一对一查询之注解开发2.4 一对多查询之注解开发2.5 多对多查询之注解开发三、Mybatis缓存3.1 一级缓存3.2 二级缓存四、Mybatis插件4.1 Mybatis插件简介4.2 Mybatis插件原理4.3 自定义Myba

RabbitInTheGrass的博客 3096

2021秋招IC验证面经-ARM中国/中科芯/飞腾/地平线/中兴

中科芯 (央企福利待遇好,但是百分百不解决户口,适合当地人进去躺平。) 现场面试,三个面试官,时间大约40min 首先介绍一下自己,介绍一下项目。所做项目用到了FIFO吗,深度是多少,位宽是多少,仲裁算法是什么? 验证环境中的reference model是自己写的还是本身就有的,仲裁怎么在参考模型中实现,参考模型怎么获取寄存器的值? 怎么配置RTL寄存器,通过平台的寄存器模型进行寄存器配置,寄存器模型里边的方法,写一个寄存器或读一个寄存器怎么实现? 寄存器如何实现前门访问和后门访问,后门访问时

weixin_48014653的博客 6319

VoIP概述

VoIP统一通信与VoIPVoIP与传统电话比较VoIP各项产品设备的类型及应用 统一通信与VoIP 统一通信指的是把计算机与传统通信技术统一成一体的新通信模式,融合计算机网络与传统通信网络在一个网络平台上,实现电话、传真、数据传输、音视频会议、呼叫中心、即时通信等众多应用服务 VoIP又称IP电话或IP网络电话,是Voice Over IP的缩写,这种技术通过对语音信号进行编码数字化,压缩处理成压缩帧,然后转换成为IP数据包在TCP/IP网络上进行传输,从而达到了在IP网络上进行语音通信目的 VoIP与传

kaminao的博客 4364

Mybatis 基于注解开发之多表查询

1、多表查询 当我们使用两张或者两张以上的表联合查询时,就会产生四种关系,一对一、一对多、多对一、多对多。前面的文章曾经用xml配置文件的形式讲解了这几种关系。在这里我们将会用注解的方式简述一下如何实现多表联合查询,项目的目录与前几个文章的项目是一样的不一样的地方就是IUserDao和IAccountDao接口多了注解,xml配置文件消失。 2、一对一查询 项目结构参考https://blog.c...

Zystem 4586

零差云控 ZeroErr eRob 电机 CAN、CANopen、EtherCAT、ROS2 机器人开发详细教程

TwinCAT 3(Windows 控制与自动化技术)是 Beckhoff 提供的开发平台,可将任何兼容 PC 转变为实时控制系统,用于管理各种类型的工业自动化系统,如 PLC(可编程逻辑控制器)、运动控制、机器人等。

机器人控制与仿真应用 1万+

MyBatis(多表关联)

MyBatis-多表关联多表关联:一对一关联(重要)步骤创建数据库表创建模块编写实体类接口映射UserMapper.xml的配置测试注意多表关联:一对多关联(重要)步骤创建数据库表编写实体类声明UserMapper接口方法UserMapper.xml映射配置文件接口映射文件配置UserMapper.xml测试多表关联:多对多关联用户与角色多对多关系模型步骤创建角色表和中间表查询 1 号用户有哪些角色类之间的关系Role 角色实体类,对应多个用户声明 UserMapper 接口配置 UserMapper.xm

weixin_50648720的博客 2958

SWC_RTE01-AutoSAR架构【AutoSAR架构设计概述】

1 基于AutoSAR架构的概述 1.1架构层面:功能可以细分子功能,各个子功能需要交互。 -大功能可以通过Autosar组件Composition去表示; -各个子功能一般具有不可分割性,可以通过Autosar原子组件Component去表示; -各个子功能的交互可以通过接口去通信和交互; -各个子功能的行为可以通过内部行为去表示;具体表现为Runnable的设计;架构设计的时候不考虑具体的逻辑实现;只会关注Ruannble的触发事件或周期;数据访问的一致性问题;具体逻辑设计可通过模版c文件实现或通过基于

8452

研制过程评审活动(三)工程研制阶段

工程研制阶段主要任务、及评审活动

Abel的博客 2388

MyBatis——关于一级缓存 & 二级缓存的案例详解

MyBatis——关于一级缓存 & 二级缓存的案例详解

贝尔摩德苦艾酒 8127

3. NVIDIA GPU Xid 常见错误码全解析、故障定位与标准化处理方案

摘要: Xid是NVIDIA显卡驱动记录的硬件/软件异常日志,通过dmesg等工具可获取,包含PCI总线、GPU编号、故障码等信息,是诊断显卡问题的核心依据。Xid故障分为四类:应用程序类(如代码错误,Xid13/31)、显存ECC硬件类(如显存损坏,Xid48/63)、链路/供电温控类(如PCIe故障,Xid74/79)和GSP固件类(如静电干扰,Xid119/154)。排查流程包括日志采集、软件修复(如重启进程、升级驱动)、硬件检查(如PCIe链路状态)及断电复位(针对GSP故障)。预防措施包括监控EC

jundao1997的专栏 707

mybatis二级缓存架构原理

一级缓存 与springboot集成时一级缓存不生效原因以及解决方案 如何解决这个问题? 要知道如何解决这个问题, 二级缓存 为什么mybatis默认不开启二级缓存? 不推荐使用。 ...

修理男爵的博客 3857

YOLO11-Seg优化:卷积变体系列篇 | 动态蛇形卷积(Dynamic Snake Convolution) | ICCV2023

动态蛇形卷积(Dynamic Snake Convolution),增强微小特征提取能力,引入到YOLO11-Seg,与C3k2结合实现二次创新

会AI的学姐 371

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

2.4.4 Mybatis 局部/全局延迟加载, 一/二级缓存, 使用Mybatis注解, 增删改查, 一对一/多, 多对多, 多表查询, 注解二级缓存, 注解延迟加载

Mybatis任务三:加载策略及注解开发 一 MyBatis加载策略 1.1 什么是延迟加载? 问题 通过前面的学习,我们已经掌握了Mybatis中一对一,一对多,多对多关系的配置及实现,可以实现 对象的关联查询。实际开发过程中很多时候我们并不需要总是在加载用户信息时就一定要加载他的订单 信息。此时就是我们所说的延迟加载。 举个栗子 延迟加载 就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载。 1.2 实现 1.2.1 局部延迟加载 在association和c

chengh1993的博客 446

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Mybatis详细之开启一级缓存与二级缓存详细步骤

MyBatis会将查询结果存储在缓存当中,当下次执行相同的SQL时不访问数据库,而是直接从缓存中获取结果,从而减少服务器的压力。

whs15193553607的博客 1885

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

mybatis day03 多表查询、注解CRUD、注解多表查询、一级缓存、二级缓存

mybatis day03 多表查询、注解CRUD、注解多表查询、一级缓存、二级缓存

weixin_44504809的博客 207

MyBatis缓存机制:一级与二级缓存详解

一级缓存与二级缓存的原理与实战 MyBatis提供两级缓存优化查询性能:一级缓存为SqlSession级别,默认开启,仅在单次会话内有效;二级缓存为Mapper级别,需手动配置,支持跨会话共享。一级缓存通过LocalCache实现,写操作会自动清空;二级缓存要求实体类序列化,通过Cache接口实现,写操作会清空当前Mapper缓存。本文详细分析了两级缓存的工作原理、配置方法、使用场景及优化技巧,包括缓存失效场景、序列化要求、分布式缓存集成方案等,帮助开发者合理运用缓存提升系统

2401_83675559的博客 1366

MyBatis系统学习(四)——MyBatis的关联映射和缓存机制

一对一(One-to-One):两个表中一条记录对应另一个表中的一条记录。一对多(One-to-Many):一个表中一条记录对应另一个表中的多条记录。多对多(Many-to-Many):两个表中的多条记录彼此关联。使用resultMap标签进行复杂的对象关系映射。通过注解来实现简单的映射。动态 SQL:MyBatis 提供了ifchoosewhenforeach等标签来处理动态 SQL,满足多变的业务需求。resultMap的使用resultMap。

2301_79858914的博客 1859

【精选必读】MyBatis关联查询及注解开发

MyBatis是一个半自动的ORM框架,其本质是对JDBC的封装。使用MyBatis不需要写JDBC代码,但需要程序员编写SQL语句。之前是apache的一个开源项目iBatis,2010年改名为MyBatis。

guojiaqi_的博客 1415
上一篇: Mybatis(二)代理开放、动态Sql语句、mybatis核心配置文件深入、Pagehelper
下一篇: Mybatis面试汇总
·小脑斧·
博客等级 码龄7年 10粉丝 46原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值