Mybatis框架使用详解

Mybatis框架使用详解,第1张

Mybatis框架使用详解 Mybatis基础 简介

MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架。

MyBatis 消除了几乎所有的 JDBC 代码和参数的手工设置以及结果集的检索。

MyBatis 使用简单的 XML 或注解用于配置和原始映射,将接口和 Java 的POJOs(普通的 Java对象)映射成数据库中的记录。

每个MyBatis应用程序主要都是使用SqlSessionFactory实例的,一个SqlSessionFactory实例可以通过SqlSessionFactoryBuilder获得。SqlSessionFactoryBuilder可以从一个xml配置文件或者一个预定义的配置类的实例获得。

用xml文件构建SqlSessionFactory实例是非常简单的事情。推荐在这个配置中使用类路径资源(classpath resource),但其实可以使用任何Reader实例,包括用文件路径或 file:// 开头的 url 创建的实例。MyBatis有一个实用类----Resources,它有很多方法,可以方便地从类路径及其它位置加载资源。


优点

  • MyBatis封装了JBDC底层访问数据库的细节,使我们程序猿不需要与JDBC API打交道,就可以访问数据库
  • MyBatis简单易学,程序猿直接编写SQL语句,适合于对SQL语句性能要求比较高的项目
  • SQL语句封装在配置文件中,便于统一管理与维护,降低了程序的耦合度
  • SQL代码从程序代码中彻底分离出来,可重用
  • 提供了动态SQL标签,支持编写动态SQL
  • 提供映射标签,支持对象与数据库的ORM字段关系映射

缺点

  • 过于依赖数据库SQL语句,导致数据库移植性差,更换数据库,如果SQL语句有差异,SQL语句工作量大
  • 由于xml里标签id必须唯一,导致DAO中方法不支持方法重载

SpringBoot集成Mybatis

依赖

SpringBoot官方并没有提供Mybatis的启动器,不过Mybatis官网自己实现了

		
		
            org.mybatis.spring.boot
            mybatis-spring-boot-starter
            2.1.3
        
		
        
            com.github.pagehelper
            pagehelper-spring-boot-starter
            1.2.3
               

		
		
           org.springframework.boot
           spring-boot-starter-jdbc
		

默认情况下,插件MyBatis-Spring-Boot-Starter将进行如下配置:

  • 自动检查 SpringBoot 的数据源配置并构建 DataSource 对象

  • 通过 SqlSessionFactoryBean 使用数据源构建并注册 SqlSessionFactory 对象

  • 从 SqlSessionFactory 中创建并注册一个 SqlSessionTemplate 实例,其实就是构建一个 SqlSession 对象

  • 自动扫描使用了注解@Mapper的接口映射器,并将这些映射器与SqlSessionTemplate实例进行关联,同时将它们注册到Spring容器中


常用yaml配置

mybatis:
  # 注册XML映射器,即mapper.xml文件位置。如果没有映射文件,请注释掉
  mapper-locations: classpath:mapper/**.xml
  # 配置Java类型别名包扫描路径。通过该属性可以给包中的类注册别名,注册后在 Mapper 对应的 XML 文件中可以直接使用类名,而不用使用全限定的类名(即 XML 中调用的时候可以不用包含全限包名)
  type-aliases-package: com.test.springbootssm.entity
  configuration:
    # 指定MyBatis所用日志的具体实现(输出sql语句),未指定时将自动查找。
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    # 开启自动驼峰命名规则(camel case)映射。即从经典数据库列名 A_COLUMN(下划线命名)到经典 Java 属性名 aColumn(驼峰命名)的类似映射
    map-underscore-to-camel-case: true

不太常用的yaml配置

mybatis:
  ## 不常用的配置
  check-config-location: true      	 # 是否检测MyBatis运行参数配置文件
  config-location: classpath:mybatis/mybatis-config.xml		# mybatis配置文件所在路径
  type-handlers-package: test.springboot.handlers         	# 配置类型处理器包名
  executor-type: SIMPLE                                   	# 指定执行器类型
  configuration:
      default-fetch-size: 20
      default-statement-timeout: 30
      lazy-loading-enabled: true 		# 开启延时加载开关
      aggressive-lazy-loading: false 	# 将积极加载改为消极加载(即按需加载),默认值就是false
      lazy-load-trigger-methods: "" 	# 指定触发延迟加载的方法
      cache-enabled: true 				# 打开全局缓存开关(二级环境),默认值就是true
      
#MyBatis使用pageHelper分页
pagehelper:
  helper-dialect: mysql		# 配置使用哪种数据库语言,不配置的话pageHelper也会自动检测
  reasonable: true			# 启用查询合理化。如果pageNum<1,则会查询第一页;如果pageNum>pages,则会查询最后一页
  # 支持通过Mapper接口参数来传递分页参数,默认值false,分页插件会从查询方法的参数值中,自动根据上面 params 配置的字段中取值,查找到合适的值时就会自动分页。
  support-methods-arguments: true

上述配置参数最终是通过mybatis-spring-boot-autoconfigure.jar加载和配置的。


Java方式配置MyBatis运行时参数

MyBatis的运行时参数除了可以在SpringBoot的配置文件中指定,还可以通过Java编码方式设置。实际上就是在Spring容器中注册一个实现了ConfigurationCustomizer接口的Bean。

import org.springframework.context.annotation.Configuration;

@Configuration
public class MyBatisConfig {
    
    @Bean
    ConfigurationCustomizer mybatisConfigurationCustomizer() {
        return new ConfigurationCustomizer() {
            @Override
            public void customize(org.apache.ibatis.session.Configuration configuration) {
                // 在SpringBoot中以Java编码方式配置MyBatis运行时参数
                configuration.setMapUnderscoreToCamelCase(true);
                configuration.addMappers("com.test.springboot.mapper");
            }
        };
    }
}

Spring集成MyBatis

依赖

        
        
            org.mybatis
            mybatis
            ${version.mybatis}
        
		
        
            tk.mybatis
            mapper
            ${version.mybatis.mapper}
        
		
        
            com.github.pagehelper
            pagehelper
            ${version.pagehelper}
        

        
        
            org.mybatis
            mybatis-spring
            ${version.mybatis.spring}
        

        
        
            org.springframework
            spring-tx
        

        
        
            org.springframework
            spring-jdbc
        

通过Java方式注册MyBatis核心组件

通过Java方式在Spring框架中注册MyBatis的核心组件Bean,并且配置声明式事务管理。

(1)在Spring中注册MyBatis的核心组件Bean:SqlSessionFactory,SqlSession,以及Spring的事务管理器。另外,在构建SqlSessionFactory时还可以注册MyBatis的xml映射器。

@Configuration
@EnableTransactionManagement
public class MyBatisSpringConfig implements TransactionManagementConfigurer {
    @Autowired
    private DataSource dataSource;
    
    // 在Spring中注册SqlSessionFactory,在这里可以设置一下参数:
    // 1.设置分页参数
    // 2.配置MyBatis运行时参数
    // 3.注册xml映射器
    @Bean
    public SqlSessionFactory sqlSessionFactory() {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        // 设置数据源
        sqlSessionFactoryBean.setDataSource(dataSource);
        // 设置映射POJO对象包名
        // sqlSessionFactoryBean.setTypeAliasesPackage("org.chench.test.springboot.model");
        
        // 分页插件
        
        //添加插件
        //sqlSessionFactoryBean.setPlugins(new Interceptor[]{pageHelper});
        
        // 配置mybatis运行时参数
        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        // 自动将数据库中的下划线转换为驼峰格式
        configuration.setMapUnderscoreToCamelCase(true);
        configuration.setDefaultFetchSize(100);
        configuration.setDefaultStatementTimeout(30);
        
        sqlSessionFactoryBean.setConfiguration(configuration);
        
        // 在构建SqlSessionFactory时注册xml映射器
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        try {
            sqlSessionFactoryBean.setMapperLocations(resolver.getResources("classpath:mapper
    @Bean(value = "sqlSession")
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

    // Spring事务管理器
    @Bean(value = "transactionManager")
    @Override
    public PlatformTransactionManager annotationDrivenTransactionManager() {
        return new DataSourceTransactionManager(dataSource);
    }
}

(2)注册MyBatis接口映射器 MyBatis 3支持2种映射器:xml映射器和接口映射器,其中xml映射器可以在构建SqlSessionFactory时进行注册。

@Configuration
@AutoConfigureAfter(MyBatisSpringConfig.class) //注意,由于MapperScannerConfigurer执行的比较早,所以必须有该注解
public class MyBatisMapperScannerConfig {
    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer() {
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        // 设置sqlSessionFactory名
        mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
        // 设置接口映射器基础包名
        mapperScannerConfigurer.setbasePackage("org.chench.test.springboot.mapper");
        Properties properties = new Properties();
        //properties.setProperty("mappers", "org.chench.test.springboot.mapper");
        properties.setProperty("notEmpty", "false");
        properties.setProperty("IDENTITY", "MYSQL");
        mapperScannerConfigurer.setProperties(properties);
        return mapperScannerConfigurer;
    }
}

MyBatis支持2种类型的映射器:XML映射器和接口映射器,在这里以定义并使用接口映射器为例。

定义接口映射器

@Repository
public interface AccountMapper {
    @Select("select * from account where id = #{id}")
    public Account getAccountById(@Param("id") long id);
}

注意: 在这里可以使用Spring容器的注解@Repository声明MyBatis的接口映射器为一个Bean组件,这样在使用接口映射器时可以直接注入这个接口映射器Bean进行使用。


通过xml方式注册MyBatis核心组件

applicationContext-mybaits.xml




    
    
        
        
        
        
    

     
    
    
        
        
    

    
    
        
        
    


    
    
    
        
    

    
    
        
            
            
            
            
            
        
    
    
    
    
        
        
    



xml映射文件




    
    
	select * from user




Mybatis高级查询 查询结果封装
  • resultType
    如果实体的属性名与数据库表中字段名(或查询字段别名)一致,将查询结果自动封装到实体类中。

    • 如果是单条数据,mybatis直接返回封装好数据的对象
    • 如果是多条数据,mybatis会将封装好的多个对象放入list集合中
  • resutlMap
    如果实体的属性名与数据库表中字段名不一致,使用ResutlMap实现手动映射封装到实体类中

    resutlMap的属性说明 :

    
        
        
        
      						
      	
        
        
    

    xml映射文件:

    
        
        
        
        
        
    
    
    
        select * from user where id = #{id} and username = #{username}
    
    
    
    
        
        select * from user where id = #{param1} and username = #{param2}
    
    

    模糊查询
    • 方式1:sql中使用 concat函数进行模糊匹配拼接【推荐】

    • 方式2:sql中使用 || (字符串连接符)进行模糊匹配拼接【推荐】

    • 方式3:java中添加模糊匹配

      ​ 缺点:在java中出现了sql通配符,产生了耦合性问题,不太推荐使用

      // java示例
      List list = userDao.findLikeUsername("%王%")
      
    • 方式4:sql中拼接模糊匹配(%#{usenme}%)

      ​ 缺点:只支持mysl5.5以上版本,oracle不支持该写法

    • 方式5:sql中拼接模糊匹配(%${value}%)

      ​ ${} 字符串拼接 ,如果接收简单数据类型 名称只能是:${value}

      ​ 缺点:这种方式的底层使用的是编译对象statement做的查询,会出现sql注入问题,开发不能使用

    xml文件:

    
    	select * from user where username like ('%' || #{username} || '%');
    
    
    
    
        select * from user where username like '%#{username}%'
    
    
    
    
        select * from user
        
            order by ${order_by} desc			
        
    
    
    
        select * from user
        
            where id=#{id}
        
    
    

    Mybatis映射文件深入 动态sql if 标签

    if 标签:

    判断语句(单条件分支)。必须结合 test 属性联合使用。

    常用场景:

    • 在 WHERe 条件中使用 if 标签。根据条件判断动态拼接查询条件。
    • 在 UPDATE 更新列中使用 if 标签。只更新有变化的字段, 空值不更新。
    • 在 INSERT 动态插入中使用 if 标签。只有非空属性才插入。
    • 在 SELECT 动态查询字段使用 if 标签。根据条件动态确定查询字段。

    mapper接口方法:

    public List findByIdAndUsernameIf(User user);
    

    xml文件:

    
        select * from user
        
            
                
                    and id = #{id}
                
                
                     and username like concat(concat('%',#{username}),'%')
                
                
                    and 1 = 1
                
            
        
    
    

    set 标签

    可以去掉 set 标签中的最后一个条件的 逗号

    mapper接口方法:

    public void updateIf(User user);
    

    xml方法:

    
        update user 
        
            
                username=#{username},
            
            
                birthday=#{birthday},
            
            
                sex = #{sex},
            
            
                address = #{address},
            
        
        where id = #{id}
    
    

    foreach 标签

    做数据的循环遍历

    * 例如:
    	select * from user where id in (1,2,3)
    	在这样的语句中,传入的参数部分必须依靠 foreach遍历才能实现。
    

    foreach 标签中的属性:

    • collection:必填, 被遍历的集合(list)/数组(array)/Map的名称
    • item:变量名。即从迭代的对象中取出的每一个值
    • index:索引的属性名。当迭代的对象为 Map 时, 该值为 Map 中的 Key.
    • open:遍历前拼接的字符串
    • close:遍历后拼接的字符串
    • separator:分隔符

    where 中使用 foreach

    mapper接口方法:

    // foreach标签 遍历
    public List findByList(List ids);
    
    public List findByArray(Integer[] ids);
    
    // 传递引用数据类型 list属性或者array属性
    public List findByPojo(QueryVo queryVo);
    

    xml文件:

    
        select * from user where
        
            #{id}
        
    
    
    
    
        select * from user where
        
            #{id}
        
    
    

    foreach 实现批量插入

    mapper接口方法:

        // 批量插入学生
        int insertList(List students);
    

    xml文件:

        
            insert into student(name, phone, email, sex, locked)
            values
            
                (
                #{student.name}, #{student.phone},#{student.email},
                #{student.sex},#{student.locked}
                )
            
        
    

    trim 标签

    trim 标签的属性

    • prefix: 当 trim 元素包含有内容时, 增加 prefix 所指定的前缀
    • prefixOverrides: 当 trim 元素包含有内容时, 去除 prefixOverrides 指定的前缀
    • suffix: 当 trim 元素包含有内容时, 增加 suffix 所指定的后缀
    • suffixOverrides:当 trim 元素包含有内容时, 去除 suffixOverrides 指定的后缀、

    set 和 where 其实都是 trim 标签的一种类型, 该两种功能都可以使用 trim 标签进行实现。

    trim 标签来实现 where 标签

    当 trim 标签中含有内容时,添加 where,且第一个为 and 或 or 时,会将其去掉;而如果没有内容,则不添加 where

    
    
    

    trim 标签来实现 set 标签

    当 trim 标签中含有内容时,添加 set,且最后的内容为 , 时,会将其去掉;而没有内容,不添加 set

    
    
    

    bind 标签

    bind 元素允许在 OGNL 表达式以外创建一个变量,并将其绑定到当前的上下文。

    如在 selectByStudentSelective 方法中,有如下

    
          and name like concat('%', #{name}, '%')
    
    

    在 MySQL 中,concat 函数支持多参数,但在 Oracle 中只支持两个参数。通过使用 bind 来让该 SQL 达到支持两个数据库的作用

    
         
         and name like #{nameLike}
    
    

    include 标签(引入sql片段)
    
        select * from user
    
    
    
    
         
        where 
        
            #{id}
        
    
    
    
    

    生成并返回主键

    往数据库中插入记录时,生成主键并将主键返回到原实体对象中。

    • 方式1:【复杂,但通用】

      既支持主键自增类型,也支持 UUID 类型的主键的生成与返回

    • 方式2:useGeneratedKeys【简单,但不通用】

      注意:这种方式仅支持主键自增类型的数据库,如 MySQL 和 sqlServer,oracle不支持

    xml文件:

    
        
            SELECT LAST_INSERT_ID() FROM DUAL
        
        insert into user(username, birthday, sex, address) values(#{username}, #{birthday}, #{sex}, #{address})
    
    
    
    
        insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
    
    

    多表查询 表关系及xml标签配置介绍
    一对一   	订单与用户。查询站在订单角度:一个订单只能属于一个用户
    一对多   	用户和订单。查询站在用户角度:一个用户可以拥有多个订单
    多对一		订单和用户。多个订单,可以被一个用户拥有
    多对多   	用户和角色。	- 站在用户角度:一个用户可以拥有多个角色
    					  - 站在角色角度:一个角色可以被多个用户拥有
    
    
    mybatis:一个表是一个实体的映射(user  orders)
    实体: 实体属性、集合属性
    1 v 1: 实体属性
    1 v N: 1的一方有多的一方的集合属性  多的一方有1的一方的实体对象
    
    
    * 一对一配置:使用+做配置
    	association:
        	property:关联的实体属性名
        	javaType:关联的实体类型(使用别名)
    
    * 一对多配置:使用+做配置
    	collection:
    		property:关联的集合属性名
    		ofType:关联的集合泛型类型(使用别名)
    
    * 多对多配置:使用+做配置
    	collection:
    		property:关联的集合属性名
    		ofType:关联的集合泛型类型(别名)
    		
    * 多对多的配置跟一对多很相似,区别在于SQL语句的编写。
    

    多表查询和嵌套查询的实体类

    Orders(订单)实体类

    @Data
    public class Orders {
        private Integer id;
        private Date ordertime;
        private Double money;
        // 订单所属的用户
        private User user;
    }
    

    User(用户)实体类

    @Data
    public class User {
        private Integer id;
        private String username;
        private Date birthday;
        private String sex;
        private String address;
        
        // 一个用户有多个角色
        private List roleList;
    
        // 一个用户有多个订单
        private List orders;
    }
    

    Role(角色)实体类

    @Data
    public class Role {
        private Integer id;
        private String roleName;
        private String roleDesc;
    }
    

    一对一(多对一)

    一对一查询的实例:

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

    OrdersMapper.xml映射文件(一对一映射关系)

    
    
    
    
        
        
                
                
                
                
                
                
                        
                        
                        
                        
                        
                
        
        
        
        
            select *, o.id as iid from user u left join orders o on u.id=o.uid where u.id=#{id}
        
    
    

    多对多(二个一对多)

    多对多的查询的实例:

    需求: 查询某个用户的所有角色或者是某个角色的所有用户

    • 站在用户角度,一个用户可以拥有多个角色
    • 站在角色角度,一个角色可以被多个用户拥有
    • 所以 mybatis框架多对多的实现,跟一对多的步骤是一样的,区别点在于sql语句

    UserMapper.xml映射文件

    
    
    
        
    	
                
                
                
                
                
                
                
                
                        
                        
                       
                
        
        
        
        
            select * from orders where id=#{id}
        
    
    
    
    
    
        
        
            select * from user where id=#{id}
        
    
    
    
    
    
       
        
        
            select * from user where id=#{id}
        
    
    
    
    
    
        
        
            
            
            
        
        
        
        
    

  • 通用mapper

    官方网站:https://mybatis.io/

    github源码:https://github.com/abel533/Mapper

    gitee源码:https://gitee.com/free/Mapper/wikis/Home

    简介、依赖及常用配置

    通用Mapper是简化mybatis *** 作的一个框架,是为了解决单表增删改查,基于Mybatis的插件。开发人员不需要建立 xml 映射文件编写 SQL,不需要在dao接口中增加方法,只需要写好实体类,用注解跟数据库的表和字段建立映射关系,然后在dao接口继承baseMapper并指定泛型,就能支持相应的增删改查方法。在service实现类中,直接调用相关方法,就可以执行简单的单表CRUD。


    SpringBoot官方并没有提供通用Mapper的启动器,不过通用Mapper的作者为自己的插件编写了启动器

    注意:一旦引入了通用Mapper的启动器,会覆盖Mybatis官方启动器的功能,因此需要移除对官方Mybatis启动器的依赖。

    (把mybatis相关的配置文件删除、把引导类上mapperScan注解删除、把mybatis的启动器删除)

            
            
                tk.mybatis
                mapper-spring-boot-starter
                2.1.5
            
    

    启动类上若有@MapperScan注解,则需修改为通用Mapper中自带的:

    import tk.mybatis.spring.annotation.MapperScan;
    

    修改mapper接口

    public interface UserMapper extends baseMapper {
    }
    

    在实体类上添加注解@Table,主键上添加@Id

    @Data
    @Table(name = "tb_user")	// 指定要映射的数据库中的哪个表
    public class User {
        
        @Id		//表示该成员变量是主键id
        private Long id;
        
        private String userName;
        
        private String password;
    }
    

    常用API

    **根据主键id查询:**selectByPrimaryKey(id);

    添加数据:

    • insertSelective(brand):添加数据,如果添加的数据中有为null的字段,则不进行更改。推荐,如果有特需,则用下面方式

    • insert(brand):添加数据,不管要添加的数据是否为null,都进行更改,如果为null则将数据库中的该字段修改为null

    根据id更新数据:

    • updateSelective(brand):更新数据,如果添加的数据中有为null的字段,则不进行更改。推荐,如果有特需,则用下面方式

    • update(brand):更新数据,不管要添加的数据是否为null,都进行更改,如果为null则将数据库中的该字段修改为null

      注意:根据id更新数据,那么传入的 pojo 对象中的 id 字段一定要有值,否则它不知道修改哪条数据

    **根据id删除数据:**deleteByPrimaryKey(id);


    拓展了解 Mybatis核心文件概述

    1)environments标签

    数据库环境配置

    1. 其中,事务管理器(transactionManager)类型有两种:
    • JDBC:
      这个配置就是直接使用了JDBC 的提交和回滚设置,由mybatis自己手动控制事务
    • MANAGED:
      这个配置几乎没做什么。它从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期。
      例如:mybatis与spring整合后,事务交给spring容器管理。
    1. 其中,数据源(dataSource)常用类型有二种:
    • UNPOOLED:
      这个数据源的实现只是每次被请求时打开和关闭连接。
    • POOLED:
      这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来。使用的是mybatis自带的

    2)properties标签

    第三方属性配置

    实际开发中,习惯将数据源的配置信息单独抽取成一个properties文件

    	 	
    	 
    	 
            
            
                
                
                
                
                    
                    
                    
                    
                
            
        
    

    3)typeAliases标签

    实体类型别名配置

    	
            
            
            
            
            
        
    


    4)mappers标签

    映射关系配置(加载映射配置文件)

    	
    	
    

    核心配置文件标签顺序


    Mybatis的API概述

    1)Resources

    专门用于加载mybatis核心配置文件,返回的 io流

    InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
    

    2)SqlSessionFactoryBuilder

    专门用于生产SqlSessionFactory工厂对象

    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
    

    3)SqlSessionFactory

    一个项目只有一个工厂对象,生产sqlSession对象

    // 需要手动提交事务,DML语句才会持久化到数据库中
    SqlSession openSession();	// 【推荐】
    	
    // 设置是否开启自动提交,如果设置为true,开启自动提交事务
    SqlSession openSession(boolean autoCommit);
    	参数说明
    		true:每一条DML类型语句都会自动提交事务
    		false(默认值):需要手动提交事务
    

    4)SqlSession

    是mybatis核心对象,可以对数据库进行CRUD基本 *** 作

    //  方法
     T selectOne(String statement, Object parameter);
     List selectList(String statement, Object parameter);
    int insert(String statement, Object parameter);
    int update(String statement, Object parameter);
    int delete(String statement, Object parameter);
        
    // 事务
    void commit();
    void rollback();
    

    MyBatis延迟加载(懒加载)

    Mybatis的延迟加载是针对嵌套查询而言的,是指在进行查询的时候先只查询最外层的SQL,对于内层SQL将在需要使用的时候才查询出来。

    使用延迟加载的场景:一对多、多对多

    不推荐使用延迟加载的场景:一对一(使用 立即加载)

    特别注意:延迟加载是基于 嵌套查询 组合使用


    1)局部延迟加载

    * 需要手动在每一个select相关标签中单独配置
    	、
    		fetchType="lazy"  懒加载
    		fetchType="eager" 立即加载
    

    2)全局延迟加载

    lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载,特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。默认值为false。

    	
        
            
            
        
    

    若是pringboot集成,在yaml配置文件中配置开启延迟加载。

    mybatis:
      configuration:
        lazy-loading-enabled: true 		#开启延时加载开关
    

    注意:如果全局配置了延迟加载,那么一对一也会起作用

    可以为一对一设置局部的立即加载,因为局部优先级高于全局延迟加载

     
    
    

    3)指定触发延迟加载的方法配置

    lazyLoadTriggerMethods 默认情况下仅仅支持自动将 equals,clone,hashCode,toString 这几个方法定义为延迟加载的加载触发方法。

    * 在SqlMapConfig.xml核心配置文件,设置全局参数
    	
    		
    		
    	
    

    若是springboot集成,在yaml配置文件中配置

    mybatis:
      configuration:
        lazy-loading-enabled: true 		# 开启延时加载开关
        aggressive-lazy-loading: false 	# 将积极加载改为消极加载(即按需加载),默认值就是false
        # 指定触发延迟加载的方法
        lazy-load-trigger-methods: "doLazyLoadingNow,equals,clone,hashCode,toString"
    

    MyBatis缓存

    参考:https://blog.csdn.net/jinhaijing/article/details/84230810

    缓存是服务器内存的一块区域。经常访问但又不会时时发生变化的数据适合使用缓存。

    mybatis也支持缓存:提高查询速度,减轻数据库访问压力。


    一级缓存(本地缓存)

    MyBatis自带一级缓存且不可卸载

    当执行查询以后,查询的结果会同时缓存到SqlSession为我们提供的一块区域中,该区域的结构是一个Map,当再次查询同样的数据时,mybatis会先去sqlsession中查询缓存,有的话直接拿出来用。当SqlSession对象消失时,mybatis的一级缓存也就消失了,同时一级缓存是SqlSession范围的缓存,当调用SqlSession的修改、添加、删除、commit(),close等方法时,就会清空一级缓存。

    特点:随着sqlSession的创建而存在,随着SqlSession的销毁而销毁

    简称:sqlSession级别的缓存


    一级缓存失效的四种情况:

    • sqlSession不同(会话不同)

    • sqlSession相同,查询缓存中没有的数据

    • sqlSession相同,但两次查询之间执行了增删改 *** 作

      说明:为了防止增删改对当前数据的影响,即使查的同一个对象,也会重新查数据库

      原因:每个增删改标签都有默认刷新缓存配置:flushCache=“true”(刷新一级和二级缓存)

    • sqlSession相同,但手动清楚了一级缓存(缓存清空)

      手动清空一级缓存:openSession.clearCache();

    没有使用到当前一级缓存的情况,就会再次向数据库发出查询


    二级缓存(全局缓存)

    基于 mapper.xml 中 namespace 命名空间级别的缓存,即同一个 namespace 对应一个二级缓存。两个mapper.xml的namespace如果相同,则这两个mapper执行sql查询到数据将存在相同的二级缓存区域中。

    也称为SqlSessionFactory级别的缓存,由同一个SqlSessionFactory对象创建的多个SqlSession共享其缓存,但是其中缓存的是数据而不是对象,所以从二级缓存再次查询出得结果的对象与第一次存入的对象是不一样的。

    注意:不是程序自带的,需要配置。仅做了解,一般不推荐使用(一般使用Redis缓存)。

    配置流程:

    1. 在核心配置文件 SqlMapConfig.xml 中开启二级缓存(可以省略)

      
          
          
      
      

      若是springboot集成,在yaml配置文件中配置开启二级缓存(可以省略)

      mybatis:
        configuration:
          cache-enabled: true #打开全局缓存开关(二级环境),默认值就是true
      
    2. 在mapper配置文件中开启使用二级缓存

      
      
      
      	
          
      	
      
       
       	 默认 flushCache=“false”:如果 flushCache=true; 则每次查询之后都会清空缓存;一级和二级缓存都无法使用。


    多数据库支持

    如果配置了 DatabaseIdProvider,可以在动态代码中使用名为 “_databaseId” 的变量来为不同的数据库构建特定的语句。

    示例:

    
        
            
                select seq_users.nextval from dual
            
            
                select nextval for seq_users from sysibm.sysdummy1"
            
        
        insert into users values (#{id}, #{name})
    
    

    动态 SQL 中的插入脚本语言

    MyBatis 从 3.2 版本开始支持插入脚本语言,这允许插入一种语言驱动,并基于这种语言来编写动态 SQL 查询语句。

    可以通过实现以下接口来插入一种语言:

    public interface LanguageDriver {
      ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql);
      SqlSource createSqlSource(Configuration configuration, XNode script, Class parameterType);
      SqlSource createSqlSource(Configuration configuration, String script, Class parameterType);
    }
    

    实现自定义语言驱动后,就可以在 mybatis-config.xml 文件中将它设置为默认语言:

    
      
    
    
      
    
    

    或者,也可以使用 lang 属性为特定的语句指定语言:

    
    
    * @Result:实现结果集封装,代替了
    
    * @Results:可以与@Result 一起使用,封装多个结果集,代替了
    

    注解对用户表实现增删改查 *** 作

    import cn.test.doman.User;
    import org.apache.ibatis.annotations.*;
    
    import java.util.List;
    
    // 注解的单表crud *** 作
    @Mapper
    public interface UserMapper {
    
        //1 根据id做查询
        @Select("select * from user where id =#{id}")
        public User findById(int id);
    
    
        //2 全查
        @Select("SELECT id AS iid,username AS name,birthday AS bir,sex AS se,address AS addr FROM USER")
        @Results({
                
                @Result(column = "iid",property = "id",id=true),
                @Result(column = "name",property = "username"),
                @Result(column = "bir",property = "birthday"),
                @Result(column = "se",property = "sex"),
                @Result(column = "addr",property = "address")
        })
        public List findAll();
    
    
        //3 新增
        @Insert("insert into user(username,birthday,sex,address) "
                + "values(#{username},#{birthday},#{sex},#{address})")
        public void save(User user);
        
        //4 修改
        @Update("update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} "
                + "where id=#{id}")
        public void update(User user);
        
        //5 删除
        @Delete("delete from user where id=#{id}")
        public void delete(int id);
    }
    

    多表注解

    注解开发的多表查询是嵌套查询方式

    @Results	代替的是标签。该注解中可以使用单个@Result注解,也可以使用@Result集合。
    			使用格式:@Results({@Result(), @Result()})或@Results(@Result())
    			
    @Result		代替标签和标签
    			@Result中属性介绍:
    				column:数据库的列名
    				property:需要装配的属性名
    				one:需要使用@One注解(@Result(one=@One ()))
    				many:需要使用@Many注解(@Result(many=@Many ()))
    				
    @One(一对一)	代替了标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。
    				@One注解属性介绍:
    					select:指定用来多表查询的 sqlmapper
    				使用格式:@Result(column=" ", property=" ", one=@One(select=""))
    				
    @Many(一对多)	代替了标签,是多表查询的关键,在注解中用来指定子查询返回对象集合。
    				使用格式:@Result(column=" ", property=" ", many=@Many(select=""))
    

    1)一对一

    import org.apache.ibatis.annotations.One;
    import org.apache.ibatis.annotations.Result;
    import org.apache.ibatis.annotations.Results;
    import org.apache.ibatis.annotations.Select;
    
    @Mapper
    public interface OrdersMapper {
    
        // 查询订单
        @Select("select * from orders where id=#{id}")
        @Results({
                @Result(column = "id",property = "id",id = true),
                @Result(column = "ordertime",property = "ordertime"),
                @Result(column = "money",property = "money"),
                
                @Result(one=@One(select = "cn.test.mapper.UserMapper.findById")
                        ,property = "user",javaType = User.class, column = "uid")
        })
        public Orders findOrders(int id);
    }
    
    @Mapper
    public interface UserMapper {
    
        //1 根据id做查询
        @Select("select * from user where id =#{id}")
        public User findById(int id);
    }
    

    2)一对多

    @Mapper
    public interface UserMapper {
    
        //1 根据id做查询
        @Select("select * from user where id =#{id}")
        @Results({
                @Result(column = "id",property = "id",id=true),
                @Result(column = "username",property = "username"),
                @Result(column = "birthday",property = "birthday"),
                @Result(column = "sex",property = "sex"),
                @Result(column = "address",property = "address"),
                
                @Result(many = @Many(select = "cn.test.mapper.OrdersMapper.findOrdersList"),
                        property = "ordersList",javaType =List.class,column = "id")
        })
        public User findById(int id);
    }    
    
    @Mapper
    public interface OrdersMapper {
    	
        @Select("select * from orders where uid=#{用户的id}")
        public List findOrdersList(int id);
    }
    

    3)多对多

    @Mapper
    public interface UserMapper {
    
        //1 根据id做查询
        @Select("select * from user where id =#{id}")
        @Results({
                @Result(column = "id",property = "id",id=true),
                @Result(column = "username",property = "username"),
                @Result(column = "birthday",property = "birthday"),
                @Result(column = "sex",property = "sex"),
                @Result(column = "address",property = "address"),
                // 组装订单orders
                @Result(many = @Many(select = "cn.test.mapper.OrdersMapper.findOrdersList"
                                     , fetchType = FetchType.LAZY)
                        , property = "ordersList",javaType =List.class,column = "id"),
    			// 组装角色
                @Result(many = @Many(select = "cn.test.mapper.RoleMapper.findRoles")
                        ,property = "roleList",javaType = List.class,column = "id")
        })
        public User findById(int id);
    }       
    
    @Mapper
    public interface RoleMapper {
    
        
        @Select("SELECT * FROM user_role ur INNER JOIN role r ON ur.rid=r.id WHERe ur.uid=#{id}")
        @Results({
                @Result(column = "id",property = "id",id=true),
                @Result(column = "role_name",property = "roleName"),
                @Result(column = "role_desc",property = "roleDesc")
        })
        public List findRoles(int id);
    }
    

    欢迎分享,转载请注明来源:内存溢出

    原文地址: http://outofmemory.cn/zaji/5685174.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存