• Mybatis要点总结


    一、了解orm框架

            1.什么是ORM框架:对象关系映射(Object Relational Mapping,简称ORM),该模式是为了解决面向对象与关系数据库互补匹配的现象的技术;orm框架是连接数据库的桥梁,主要提供了人持久化与表之间的映射关系,ORM框架在运行时就能参照映射文件的信息,把对象持久化到数据建库中;

            2.ORM框架的主要作用:为了解决面向对象关系与关系数据库互补匹配的问题;

            3.ORM常用框架:

            (1)Hibernate全自动映射框架,需要些hql语句

            (2)iBATIs半自动框架,自己编写sql语句,可操作性强

            (3)mybits半自动ORM映射框架

            (4)eclipseLink

            (5)JFinal

            4. ORM的优缺点:
            优点:
            (1)提高开发效率,降低开发成本
            (2)使开发更加对象化
            (3)可移植
            (4)可以很方便地引入数据缓存之类的附加功能
            缺点:
            (1)自动化进行关系数据库的映射需要消耗系统性能。其实这里的性能消耗还好啦,一般来说都可以忽略之。
            (2)在处理多表联查、where条件复杂之类的查询时,ORM的语法会变得复杂。

    二、半自动与全自动的区别

            Hibrnate和mybatis是当前流行的ORM框架。hibernate对数据库结构提供了较为完整的封装。mybatis主要着力点在于java对象与SQL之间的映射关系。

           Hibrnate:使用Hibernate查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以Hibernate是全自动ORM映射框架;

            Mybits:在查询关联对象或关联集合对象时,需要手动编写sql来完成,所以Mybits是半自动ORM映射框架;

    三、动态sql一对一、一对多、多对多的理解

            前提:创建user表和orders表

    1. package com.itheima.domain;
    2. import java.util.Date;
    3. import java.util.List;
    4. public class User {
    5. private int id;
    6. private String username;
    7. private String password;
    8. private Date birthday;
    9. //当前用户具备哪些角色
    10. private List<Role> roleList;
    11. public List<Role> getRoleList() {
    12. return roleList;
    13. }
    14. public void setRoleList(List roleList) {
    15. this.roleList = roleList;
    16. }
    17. //描述的是当前用户具有的订单
    18. private List<Order> orderList;
    19. public List<Order> getOrderList() {
    20. return orderList;
    21. }
    22. public void setOrderList(List orderList) {
    23. this.orderList = orderList;
    24. }
    25. public Date getBirthday() {
    26. return birthday;
    27. }
    28. public void setBirthday(Date birthday) {
    29. this.birthday = birthday;
    30. }
    31. public int getId() {
    32. return id;
    33. }
    34. public void setId(int id) {
    35. this.id = id;
    36. }
    37. public String getUsername() {
    38. return username;
    39. }
    40. public void setUsername(String username) {
    41. this.username = username;
    42. }
    43. public String getPassword() {
    44. return password;
    45. }
    46. public void setPassword(String password) {
    47. this.password = password;
    48. }
    49. @Override
    50. public String toString() {
    51. return "User{" +
    52. "id=" + id +
    53. ", username='" + username + '\'' +
    54. ", password='" + password + '\'' +
    55. ", birthday=" + birthday +
    56. ", roleList=" + roleList +
    57. '}';
    58. }
    59. }
    1. package com.itheima.domain;
    2. import java.util.Date;
    3. public class Order {
    4. private int id;
    5. private Date ordertime;
    6. private double total;
    7. //当前订单属于哪一个用户
    8. private User user;
    9. public int getId() {
    10. return id;
    11. }
    12. public void setId(int id) {
    13. this.id = id;
    14. }
    15. public Date getOrdertime() {
    16. return ordertime;
    17. }
    18. public void setOrdertime(Date ordertime) {
    19. this.ordertime = ordertime;
    20. }
    21. public double getTotal() {
    22. return total;
    23. }
    24. public void setTotal(double total) {
    25. this.total = total;
    26. }
    27. public User getUser() {
    28. return user;
    29. }
    30. public void setUser(User user) {
    31. this.user = user;
    32. }
    33. @Override
    34. public String toString() {
    35. return "Order{" +
    36. "id=" + id +
    37. ", ordertime=" + ordertime +
    38. ", total=" + total +
    39. ", user=" + user +
    40. '}';
    41. }
    42. }

    在sqlMapConfig.xml中加载映射关系

    1. <mappers>
    2. <package name="com.itheima.mapper">package>
    3. mappers>

       在web层中应用

    1. package com.itheima.test;
    2. import com.itheima.domain.Order;
    3. import com.itheima.domain.User;
    4. import com.itheima.mapper.OrderMapper;
    5. import com.itheima.mapper.UserMapper;
    6. import org.apache.ibatis.io.Resources;
    7. import org.apache.ibatis.session.SqlSession;
    8. import org.apache.ibatis.session.SqlSessionFactory;
    9. import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    10. import org.junit.Before;
    11. import org.junit.Test;
    12. import java.io.IOException;
    13. import java.io.InputStream;
    14. import java.util.List;
    15. public class MyBatisTest2 {
    16. private OrderMapper mapper;
    17. @Before
    18. public void before() throws IOException {
    19. InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
    20. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
    21. SqlSession sqlSession = sqlSessionFactory.openSession(true);
    22. mapper = sqlSession.getMapper(OrderMapper.class);
    23. }
    24. }

            1.一对一:

                    orders—>user:一个订单只由一个用户创建,一对一

                    在测试类中实现测试一对一方法

    1. package com.itheima.test;
    2. import com.itheima.domain.Order;
    3. import com.itheima.domain.User;
    4. import com.itheima.mapper.OrderMapper;
    5. import com.itheima.mapper.UserMapper;
    6. import org.apache.ibatis.io.Resources;
    7. import org.apache.ibatis.session.SqlSession;
    8. import org.apache.ibatis.session.SqlSessionFactory;
    9. import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    10. import org.junit.Before;
    11. import org.junit.Test;
    12. import java.io.IOException;
    13. import java.io.InputStream;
    14. import java.util.List;
    15. public class MyBatisTest2 {
    16. private OrderMapper mapper;
    17. @Before
    18. public void before() throws IOException {
    19. InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
    20. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
    21. SqlSession sqlSession = sqlSessionFactory.openSession(true);
    22. mapper = sqlSession.getMapper(OrderMapper.class);
    23. }
    24. @Test
    25. public void test(){
    26. Order orders = mapper.findByOid(1);
    27. System.out.println(orders);
    28. }
    29. }

    OrderMapper
    接口实现代码:

    1. @Select("select * from orders o,user u where o.id=#{id} and o.uid=u.id")
    2. @Results({
    3. @Result(column = "id",property = "id"),
    4. @Result(column = "ordertime",property = "ordertime"),
    5. @Result(column = "total",property = "total"),
    6. @Result(
    7. property = "user", //要封装的属性名称
    8. column = "uid", //根据那个字段去查询user表的数据
    9. javaType = User.class, //要封装的实体类型
    10. //select属性 代表查询那个接口的方法获得数据
    11. one = @One(select = "com.itheima.mapper.UserMapper.findById")
    12. )
    13. })
    14. public Order findByOid(int id);

     

            2.一对多:

                    user---->orders:一个用户可以创建多个订单,一对多

                    测试类实现代码:

    1. package com.itheima.test;
    2. import com.itheima.domain.Order;
    3. import com.itheima.domain.User;
    4. import com.itheima.mapper.OrderMapper;
    5. import com.itheima.mapper.UserMapper;
    6. import org.apache.ibatis.io.Resources;
    7. import org.apache.ibatis.session.SqlSession;
    8. import org.apache.ibatis.session.SqlSessionFactory;
    9. import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    10. import org.junit.Before;
    11. import org.junit.Test;
    12. import java.io.IOException;
    13. import java.io.InputStream;
    14. import java.util.List;
    15. public class MyBatisTest2 {
    16. private OrderMapper mapper;
    17. @Before
    18. public void before() throws IOException {
    19. InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
    20. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
    21. SqlSession sqlSession = sqlSessionFactory.openSession(true);
    22. mapper = sqlSession.getMapper(OrderMapper.class);
    23. }
    24. @Test
    25. public void test(){
    26. Order orders = mapper.findByOid(1);
    27. System.out.println(orders);
    28. }
    29. @Test
    30. public void test1(){
    31. List orders = mapper.findByUid(1);
    32. for (Order order : orders) {
    33. System.out.println(order);
    34. }
    35. }
    36. }

    OrderMapper
    接口实现代码:

    1. @Select("select * from orders o,user u where uid=#{uid} and o.uid=u.id")
    2. @Results({
    3. @Result(column = "id",property = "id"),
    4. @Result(column = "ordertime",property = "ordertime"),
    5. @Result(column = "total",property = "total"),
    6. @Result(
    7. property = "user", //要封装的属性名称
    8. column = "uid", //根据那个字段去查询user表的数据
    9. javaType = User.class, //要封装的实体类型
    10. //select属性 代表查询那个接口的方法获得数据
    11. one = @One(select = "com.itheima.mapper.UserMapper.findById")
    12. )
    13. })
    14. public List findByUid(int uid);

            3.多对多:

                    完善一个中间类Role

    1. package com.itheima.domain;
    2. public class Role {
    3. private int id;
    4. private int roleId;
    5. private String roleName;
    6. private String roleDesc;
    7. private Order order;
    8. private User user;
    9. public int getRoleId() {
    10. return roleId;
    11. }
    12. public void setRoleId(int roleId) {
    13. this.roleId = roleId;
    14. }
    15. public Order getOrder() {
    16. return order;
    17. }
    18. public void setOrder(Order order) {
    19. this.order = order;
    20. }
    21. public User getUser() {
    22. return user;
    23. }
    24. public void setUser(User user) {
    25. this.user = user;
    26. }
    27. public int getId() {
    28. return id;
    29. }
    30. public void setId(int id) {
    31. this.id = id;
    32. }
    33. public String getRoleName() {
    34. return roleName;
    35. }
    36. public void setRoleName(String roleName) {
    37. this.roleName = roleName;
    38. }
    39. public String getRoleDesc() {
    40. return roleDesc;
    41. }
    42. public void setRoleDesc(String roleDesc) {
    43. this.roleDesc = roleDesc;
    44. }
    45. @Override
    46. public String toString() {
    47. return "Role{" +
    48. "id=" + id +
    49. ", roleId=" + roleId +
    50. ", order=" + order +
    51. ", user=" + user +
    52. '}';
    53. }
    54. }

                   Role---> user---->orders:一个配送员对应多个订单号和客户信息

    测试类实现代码:

    1. @Test
    2. public void test(){
    3. List list = roleMapper.findAll();
    4. for (Role role:list){
    5. System.out.println(role);
    6. }
    7. }

    接口实现代码:

    1. @Select("select * from sys_user_role ur,user u,orders o where ur.userID=u.id and ur.roleId=o.id")
    2. @Results({
    3. @Result(column = "userID",property = "id"),
    4. @Result(column = "roleId",property = "roleId"),
    5. @Result(
    6. property = "user", //要封装的属性名称
    7. column = "userID", //根据那个字段去查询user表的数据
    8. javaType = User.class, //要封装的实体类型
    9. //select属性 代表查询那个接口的方法获得数据
    10. many = @Many(select = "com.itheima.mapper.UserMapper.findById")
    11. ),
    12. @Result(
    13. property = "order",
    14. column = "roleId",
    15. javaType = Role.class,
    16. many = @Many(select = "com.itheima.mapper.OrderMapper.findByOid")
    17. )
    18. })
    19. List findAll();
    1. Role{id=1, roleId=1, order=Order{id=1, ordertime=Sat Oct 29 03:12:21 CST 2022, total=3000.0, user=User{id=1, username='张三', password='123456', birthday=null, roleList=null}}, user=User{id=1, username='张三', password='123456', birthday=null, roleList=null}}
    2. Role{id=1, roleId=2, order=Order{id=2, ordertime=Fri Oct 28 08:00:00 CST 2022, total=5800.0, user=User{id=1, username='张三', password='123456', birthday=null, roleList=null}}, user=User{id=1, username='张三', password='123456', birthday=null, roleList=null}}
    3. Role{id=2, roleId=2, order=Order{id=2, ordertime=Fri Oct 28 08:00:00 CST 2022, total=5800.0, user=User{id=1, username='张三', password='123456', birthday=null, roleList=null}}, user=User{id=2, username='李四', password='123456', birthday=null, roleList=null}}
    4. Role{id=2, roleId=3, order=Order{id=3, ordertime=Sat Oct 29 03:13:20 CST 2022, total=323.0, user=User{id=2, username='李四', password='123456', birthday=null, roleList=null}}, user=User{id=2, username='李四', password='123456', birthday=null, roleList=null}}

    四、一级缓存、二级缓存

             1.mybatis中为什么会存在缓存:

                    缓存的意义是将用户查询的数据放入缓存(内存)中,用户再去查询相应的数据就不会直接从关系数据库中查询,直接从缓存中查询,从而提高了并发开发中的系统的性能问题

             2.Mybits的一级缓存是一个sqlSession级别的缓存,只能访问自己的一级缓存数据,而二级缓存是Mapper级别的缓存,是跨SQL Session的不同sqlSession是可以共享的缓存数据;

             3.一级缓存的原理:

    第一次发出查询请求,sql 查询的结果写入SqlSession的一级缓存当中,缓存使用的数据结构是一个map

    key : hashcode + sql + sql输入参数 + 输出参数 (sql的唯一标识)
    value : 用户信息
      同一个SqlSession再次发出相同的sql,就会从缓存中读取而不走数据库,如果两次操作之间出现commit(修改、输出、添加)操作,那么本SqlSession中一级缓存区域全部清空,下次再去缓存中查不到所以要从数据库中查询,从数据库再写入一级缓存。
    https://blog.csdn.net/zy_zhangruichen/article/details/122592504icon-default.png?t=M85Bhttp://一级缓存原理

    Mybatis 中一级缓存需要注意的点 :

    Mybatis 中一级缓存是默认开启的,不需要手动配置。
    Mybatis 和 Spring 整合后进行 mapper 代理开发后,不支持一级缓存。Mybatis 和 Spring 整合,Spring 按照 mapper 的模板去生成 mapper 代理对象,模板中在最后会统一关闭 SqlSession。
            4.二级缓存原理:

    二级缓存的范围是mapper级别(mapper同一个命名空间),mapper以命名空间为单位创建缓存数据结构,结构是map。每次查询前看是否开启了二级缓存,如果开启则从二级缓存的数据结构中取缓存数据,如果二级缓存中没有取到,再从一级缓存中取,如果一级缓存也没有,那就从数据库中查询。
            (1)需要在Mybatis的配置文件中标签中配置二级缓存:

    1. <settings>
    2. <setting name="cacheEnabled" value="true"/>
    3. settings>

            (2)Mybatis的二级缓存的范围是mapper级别的,因此我们mapper如果想要使用二级缓存,还需要在对应的映射文件中配置标签

    1. <mapper namespace="com.snow.xml.SnowOracle">
    2. <cache>cache>
    3. mapper>

    五、Mybatis和Hibrnate区别

            1.Hibrnate:使用Hibernate查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以Hibernate是全自动ORM映射框架;

           2. Mybits:在查询关联对象或关联集合对象时,需要手动编写sql来完成,所以Mybits是半自动ORM映射框架;但mybits可以通过xml或注解方式灵活配置要运行的sql语句并将java对象和sql语句映射成最终执行的sql,最后将sql执行的结果在映射生成java对象

            3.Mybits学习门槛低,简单易学,程序员直接编写原生态sql,可以严格控制sql执行性灵活;但是mybits无法做到与数据库无关性,如果要实现支持多种数据库软件则需要自定义多套sql映射文件,工作量较大

            4.Hibernate 对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件(例如
    需求固定的定制化软件)如果用 hibernate 开发可以节省很多代码,提高效率。但是Hibernate 的缺点是学习门槛高,要精通门槛更高,而且怎么设计 O/R 映射,在性能和对象模型之间如何权衡,以及怎样用好 Hibernate 需要具有很强的经验和能力才行。总之,按照用户的需求在有限的资源环境下只要能做出维护性、扩展性良好的软件架构都是好架构,所以框架只有适合才是最好。

    六、分页查询插件

            1.需要在pom.xml文件中导入依赖

    1. <dependency>
    2. <groupId>com.github.pagehelper</groupId>
    3. <artifactId>pagehelper</artifactId>
    4. <version>3.7.5</version>
    5. </dependency>
    6. <dependency>
    7. <groupId>com.github.jsqlparser</groupId>
    8. <artifactId>jsqlparser</artifactId>
    9. <version>0.9.1</version>
    10. </dependency>

             2.配置分页插件: 在sqlMapConfig.xml文件中配置

    1. <!--配置分页助手插件-->
    2. <plugins>
    3. <plugin interceptor="com.github.pagehelper.PageHelper">
    4. <property name="dialect" value="mysql"></property>
    5. </plugin>
    6. </plugins>

            3.分页插件的使用

            测试类中的代码实现:

    1. @Test
    2. public void test3() throws IOException {
    3. InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
    4. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
    5. SqlSession sqlSession = sqlSessionFactory.openSession();
    6. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    7. //设置分页相关参数 当前页+每页显示的条数
    8. PageHelper.startPage(1,3);
    9. List<User> userList = mapper.findAll();
    10. for (User user : userList) {
    11. System.out.println(user);
    12. }
    13. //获得与分页相关参数
    14. PageInfo<User> pageInfo = new PageInfo<User>(userList);
    15. System.out.println("当前页:"+pageInfo.getPageNum());
    16. System.out.println("每页显示条数:"+pageInfo.getPageSize());
    17. System.out.println("总条数:"+pageInfo.getTotal());
    18. System.out.println("总页数:"+pageInfo.getPages());
    19. System.out.println("上一页:"+pageInfo.getPrePage());
    20. System.out.println("下一页:"+pageInfo.getNextPage());
    21. System.out.println("是否是第一页:"+pageInfo.isIsFirstPage());
    22. System.out.println("是否是最后一页:"+pageInfo.isIsLastPage());
    23. sqlSession.close();
    24. }

    测试结果:

     pageNum:当前页的页码
    pageSize:每页显示的条数
    size:当前页显示的真实条数
    total:总记录数
    pages:总页数
    prePage:上一页的页码
    nextPage:下一页的页码
    isFirstPage/isLastPage:是否为第一页/最后一页
    hasPreviousPage/hasNextPage:是否存在上一页/下一页
    navigatePages:导航分页的页码数
    navigatepageNums:导航分页的页码,[1,2,3,4,5]
     

    七、延时加载

            1.什么是延迟加载:Mybatis中的延迟加载,也称为懒加载,是指在进行表的关联查询时,按照设置延迟规则推迟对关联对象的select查询,例如进行一对多查询时,之查询出一方数据,当程序中需要多方数据时,mybatis在发出sql语句进行查询,这样延迟加载就可以减少对数据库压力。Mybatis的延迟加载只是对关联对象的查询有延迟设置,对于主加载对象都是直接执行查询语句

            2.加载时机:直接加载:执行完对主加载对象的 select 语句,马上执行对关联对象的 select 查询。侵入式延迟: 执行对主加载对象的查询时,不会执行对关联对象的查询。但当要访问主加载对象的详情属性时,就会马上执行关联对象的select查询。深度延迟: 执行对主加载对象的查询时,不会执行对关联对象的查询。访问主加载对象的详情时也不会执行关联对象的select查询。只有当真正访问关联对象的详情时,才会执行对关联对象的 select 查询。

            注意:延迟加载的应用要求:关联对象的查询与主加载对象的查询必须是分别进行的select语句,不能是使用多表连接所进行的select查询。因为,多表连接查询,实质是对一张表的查询,对由多个表连接后形成的一张表的查询。会一次性将多张表的所有信息查询出来。

            3.入侵式延迟加载

    ①、sqlMapConfig.xml配置文件,首先开启延迟加载,然后再配置侵入式加载

    八、Mybits中#与$的区别

    1. <setting name="lazyLoadingEnabled" value="true"/>
    2. <setting name="aggressiveLazyLoading" value="true"/>

            4.深入式延迟加载

    sqlMapConfig.xml配置文件,首先开启延迟加载,然后再配置深度加载

    1. <setting name="lazyLoadingEnabled" value="true"/>
    2. <setting name="aggressiveLazyLoading" value="false"/>

    延迟加载

  • 相关阅读:
    从实例学Kettle(一):获取股票行情数据
    前端面试题: js中对比两个对象的值是否相等? for..in 和 for...of的区别?
    刷爆力扣之子数组最大平均数 I
    Gitlab+P3C-PMD(阿里云插件)标准化你团队的代码和提交信息
    Mybatis中如何返回主键值
    天地图图层切换显示
    为啥是Spring Cloud Alibaba
    窗口看门狗使用介绍
    MTK平台Metadata的加载(4)—Q版本后
    MobaXterm两种方式上传下载文件
  • 原文地址:https://blog.csdn.net/m0_71467744/article/details/127699774