Mybatis——Mybatis表之间的关联关系和事务、缓存机制以及ORM

1. 表之间的关联关系

   我们通常说的关联关系有以下四种,一对多关联,多对一关联,一对一关联,多对多关联。关联关系是有方向的。如果是高并发的场景中,不适合做表的关联。

1.1 一对多的关联

   在多对一和一对多的关联关系中,使用订单表和客户表来描述问题。

  • 一对多:一个客户可以有多张订单,在查询时注意使用左连接查询,因为我们查询的主体使用户,一个用户可以没有订单,但是他应该显示在结果集中
    实体类创建:
    主要上以下几种方法
  • 无参构造以及包含所有属性的有参构造方法
  • set和get方法
  • toString方法

在这里插入图片描述

在这里插入图片描述

接口代码:

//根据客户id查询客户所有信息,并同时查询客户的所有订单信息
    Customer getById(Integer id);
xml文件的查询语句:
<mapper namespace="com.lcl.mapper.CustomerMapper">


    <!--
    //根据客户id查询客户所有信息,并同时查询客户的所有订单信息
    Customer getById();
    private Integer id;
    private String name;
    private Integer age;
    private List<Orders> ordersList;
    -->
    <resultMap id="customermap" type="customer">
        <!--主键绑定-->
        <id property="id" column="cid"></id>
        <!--非主键绑定-->
        <result property="name" column="name"></result>
        <result property="age" column="age"></result>
        <!--外键表的绑定-->
        <collection property="ordersList" ofType="orders">
            <!--主键绑定-->
            <!--
           private Integer id;
           private String orderNumber;
           private Double orderPrice;
           -->
            <id property="id" column="oid"></id>
            <!--非主键绑定-->
            <result property="orderNumber" column="orderNumber"></result>
            <result property="orderPrice" column="orderPrice"></result>
        </collection>
    </resultMap>
    <!--resultMap属性:,其实是通过实现数据的绑定解决实体类中的属性名和数据库表中的列名不相同的情况
    还有一方面就是在进行多表查询的时候可以实现对查询到的结果集中数据的绑定-->
    <select id="getById" parameterType="int" resultMap="customermap">
        select c.id cid,name,age,o.id oid,orderNumber,orderPrice,customer_id
        from customer c left join orders o on c.id = o.customer_id
        where c.id = #{id}
    </select>
</mapper>

测试方法:

public class MyTest {

    SqlSession sqlSession;

    @Before
    public void getSqlSession() throws IOException {
        InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
        sqlSession = factory.openSession();
    }

    @After
    public void closeSqlSession(){
        sqlSession.close();
    }
    /*
    根据客户id查询客户所有信息,并同时查询客户的所有订单信息
    Customer getById(Integer id);
    实现的是一对多的查询
    */
    @Test
    public void testCustomerGetById(){
        CustomerMapper customerMapper = sqlSession.getMapper(CustomerMapper.class);
        Customer customer = customerMapper.getById(3);
        System.out.println(customer);
    }
}

1.2 多对一的关联

  • 多个订单属于同一个用户

接口代码:

//根据主键查询订单,同时查询此订单下的客户信息
    Orders getById(Integer id);

xml文件的查询语句:

<mapper namespace="com.lcl.mapper.OrdersMapper">

    <!--
    //根据主键查询订单,同时查询此订单下的客户信息
    Orders getById(Integer id);
    private Integer id;
    private String orderNumber;
    private Double orderPrice;
    //关联此订单下的客户信息
    private Customer customer;
    -->
    <resultMap id="ordersmap" type="orders">
        <!--主键绑定-->
        <id property="id" column="oid"></id>
        <!--非主键绑定-->
        <result property="orderNumber" column="orderNumber"></result>
        <result property="orderPrice" column="orderPrice"></result>
        <!--外表中的数据绑定-->
        <association property="customer" javaType="customer">
            <id property="id" column="cid"></id>
            <!--非主键
            private Integer id;
            private String name;
            private Integer age;
            -->
            <result property="name" column="name"></result>
            <result property="age" column="age"></result>
        </association>
    </resultMap>
    <select id="getById" resultMap="ordersmap">
        select o.id oid,orderNumber,orderPrice,customer_id,c.id cid,name,age
        from orders o inner join customer c on customer_id = c.id
        where o.id = #{id}
    </select>
</mapper>

测试方法:

public class MyTest {

    SqlSession sqlSession;
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

    @Before
    public void getSqlSession() throws IOException {
        InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
        sqlSession = factory.openSession();
    }

    @After
    public void closeSqlSession(){
        sqlSession.close();
    }
    /*
    根据主键查询订单,同时查询此订单下的客户信息
    Orders getById(Integer id);
    实现的是多对一的查询
    */
    @Test
    public void testOrdersGetById(){
        OrdersMapper ordersMapper = sqlSession.getMapper(OrdersMapper.class);
        Orders orders = ordersMapper.getById(11);
        System.out.println(orders);
    }
}

1.3 多对多的关联

  • 多对多的查询使用图书和所属类别来描述问题,例如书名时MySQL和Java技术,那么毫无疑问,他就属于MySQl和Java,但是还有其他的书名也属于Java,如Java核心卷
  • 因此一本书可以属于多种类名,而一种类别又可以拥有多本书,所以图书和类别可以说明多对多的问题

实体类准备:
主要上以下几种方法

  • 无参构造以及包含所有属性的有参构造方法
  • set和get方法
  • toString方法
    在这里插入图片描述
    在这里插入图片描述
    接口代码:

在这里插入图片描述
xml文件的查询语句

<mapper namespace="com.lcl.mapper.TeacherMapper">

    <!--
    //查询教师全部信息,并且返回教师所教授知识的位置
    List<Teacher> findTeacherMessage();
    private Integer tid;
    private String tname;
    private Integer tage;
    private Classes classes;
    -->
    <resultMap id="teachermap" type="teacher">
        <!--主键映射-->
        <id property="tid" column="tid"></id>
        <!--非主键映射-->
        <result property="tname" column="tname"></result>
        <result property="tage" column="tage"></result>
        <!--外表映射
        private Integer cid;
        private Integer cname;
        -->
        <association property="classes" javaType="classes">
            <id property="cid" column="cid"></id>
            <result property="cname" column="cname"></result>
        </association>
    </resultMap>
    <select id="findTeacherMessage" resultMap="teachermap">
        select tid,tname,tage,cid,cname
        from teacher inner join classes on tid = ctid
    </select>

</mapper>

测试代码:

public class MyTest {

    SqlSession sqlSession;
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

    @Before
    public void getSqlSession() throws IOException {
        InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
        sqlSession = factory.openSession();
    }

    @After
    public void closeSqlSession(){
        sqlSession.close();
    }


    //查询全部图书,并且查询图书所属的全部类型
    //List<Books> findAll();
    //实现的时多对多的查询
    @Test
    public void testFindAll(){
        BooksMapper booksMapper = sqlSession.getMapper(BooksMapper.class);
        List<Books> booksList = booksMapper.findAll();
        booksList.forEach(books -> System.out.println(books));
    }

    //查询教师全部信息,并且返回教师所教授知识的位置
    //Teacher findTeacherMessage();
    //实现一对一的查询
    @Test
    public void testFindTeacherMessage(){
        TeacherMapper teacherMapper = sqlSession.getMapper(TeacherMapper.class);
        List<Teacher> teacherList = teacherMapper.findTeacherMessage();
        teacherList.forEach(teacher -> System.out.println(teacher));
    }
}

1.4 一对一的关联

  • 一对一的关联关系使用的是教师和班级之间的关系来说明问题:一个老师只教授一个班级,一个班级只能被一个教师教授

实体类创建:
主要上以下几种方法

  • 无参构造以及包含所有属性的有参构造方法
  • set和get方法
  • toString方法
    在这里插入图片描述
    在这里插入图片描述
    接口中方法定义:
//查询教师全部信息,并且返回教师所教授知识的位置
    List<Teacher> findTeacherMessage();

xml文件中查询语句

<mapper namespace="com.lcl.mapper.TeacherMapper">

    <!--
    //查询教师全部信息,并且返回教师所教授知识的位置
    List<Teacher> findTeacherMessage();
    private Integer tid;
    private String tname;
    private Integer tage;
    private Classes classes;
    -->
    <resultMap id="teachermap" type="teacher">
        <!--主键映射-->
        <id property="tid" column="tid"></id>
        <!--非主键映射-->
        <result property="tname" column="tname"></result>
        <result property="tage" column="tage"></result>
        <!--外表映射
        private Integer cid;
        private Integer cname;
        -->
        <association property="classes" javaType="classes">
            <id property="cid" column="cid"></id>
            <result property="cname" column="cname"></result>
        </association>
    </resultMap>
    <select id="findTeacherMessage" resultMap="teachermap">
        select tid,tname,tage,cid,cname
        from teacher inner join classes on tid = ctid
    </select>

</mapper>

测试代码:

public class MyTest {

    SqlSession sqlSession;
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

    @Before
    public void getSqlSession() throws IOException {
        InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
        sqlSession = factory.openSession();
    }

    @After
    public void closeSqlSession(){
        sqlSession.close();
    }
    //查询教师全部信息,并且返回教师所教授知识的位置
    //Teacher findTeacherMessage();
    //实现一对一的查询
    @Test
    public void testFindTeacherMessage(){
        TeacherMapper teacherMapper = sqlSession.getMapper(TeacherMapper.class);
        List<Teacher> teacherList = teacherMapper.findTeacherMessage();
        teacherList.forEach(teacher -> System.out.println(teacher));
    }

}

2. Mybatis知识点小结

2.1 事务

  • Mybatis 框架是对 JDBC 的封装,所以 Mybatis 框架的事务控制方式有两种,一种是容器进行事务管理的,一种是程序员手工决定事务的提交与回滚。
  • SqlMapConfig.xml文件中设定的事务处理的方式。

在这里插入图片描述

  • MyBatis 支持两种事务管理器类型:JDBC 与 MANAGED
  • JDBC:使用 JDBC 的事务管理机制。即,通过 Connection 的 commit()方法提交,通过 rollback()方法回滚。但默认情况下,MyBatis 将自动提交功能关闭了,改为了手动提交。即程序中需要显式的对事务进行提交或回滚。从日志的输出信息中可以看到。
  • 在获得SqlSession的时候,如果openSession()是无参或者是false,则必须手工提交事务,如果openSession(true),则为自动提交事务,在执行完增删改后无须commit(),事务自动提交。

在这里插入图片描述

2.2 缓存机制

  • 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。mybatis提供查询缓存,用于减轻数据库压力,提高数据库性能。

2.2.1 缓存执行机制

在进行数据库访问时,首先去访问缓存,如果缓存中有要访问的数据,则直接返回客户端,如果没有则去访问数据库,在库中得到数据后,先在缓存放一份,再返回客户端。如下图。
在这里插入图片描述

注意:mybaits提供一级缓存和二级缓存。默认开启一级缓存。

2.2.2 一级缓存

    第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,如果没有,从数据库查询用户信息。得到用户信息,将用户信息存储到一级缓存中。如果sqlSession去执行commit操作(执行插入、更新、删除),则清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
    第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,缓存中有,直接从缓存中获取用户信息。如果没有重复第一次查询操作。如下图。

在这里插入图片描述

@Test
public void testCacheOne() {
    //一级缓存基于SqlSession的
    //取出用户ID为7的用户
    Users u1 = mapper.getById(7);
    System.out.println("第一次访问数据库得到的u=" + u1);
    //再取一次,看看有没有访问数据库,就知道开没有开启一级缓存
    Users u2 = mapper.getById(7);
    System.out.println("第二次访问数据库得到的u=" + u2);
}
@Test
public void testCacheOneClose() {
    //一级缓存基于SqlSession的
    //取出用户ID为7的用户
    Users u1 = mapper.getById(7);
    System.out.println("第一次访问数据库得到的u=" + u1);
    //关闭session,也会清除缓存
    session.close();
    //再取一次,看看有没有访问数据库,就知道开没有开启一级缓存
    session = factory.openSession();
    mapper = session.getMapper(UsersMapper.class);
    Users u2 = mapper.getById(7);
    System.out.println("第二次访问数据库得到的u=" + u2);
}
@Test
public void testCacheOneCommit() {
    //一级缓存基于SqlSession的
    //取出用户ID为7的用户
    Users u1 = mapper.getById(7);
    System.out.println("第一次访问数据库得到的u=" + u1);

    //完成数据更新操作
    int num = mapper.update(new Users(38, "abc", new Date(), "1", "朝阳"));
    session.commit();
    System.out.println(num + "==================");

    Users u2 = mapper.getById(7);
    System.out.println("第二次访问数据库得到的u=" + u2);

2.3 ORM

ORM(Object Relational Mapping):对象关系映射
MyBatis框架是ORM非常优秀的框架.

ORM含义描述:java语言中以对象的方式操作数据,存到数据库中是以表的方式进行存储,对象中的成员变量与表中的列之间的数据互换称为映射.整个这套操作就是ORM.

持久化的操作:将对象保存到关系型数据库中 ,将关系型数据库中的数据读取出来以对象的形式封装

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇

)">
下一篇>>