MyBatis之动态和分页

        本文介绍MyBatis的动态拼接SQL、分页查询、多数据源配置等复杂的功能。

一、动态SQL语句

在需要执行一些自定义的动态SQL语句。XML配置可以使用if、choose、where等标签动态拼接SQL语句,注解提供了@InsertProvider、@UpdateProvider、@DeleteProvider和@SelectProvider等注解用来建立动态SQL语句。下面按字段更新演示动态SQL的功能。

1. 创建拼接SQL语句

首先创建UserSqlProvider类,并创建动态拼接SQL语句的方法。示例代码如下:

package org.weiz.example01.provider;
import org.weiz.example01.model.Student;
import static org.apache.ibatis.jdbc.SelectBuilder.BEGIN;
import static org.apache.ibatis.jdbc.SqlBuilder.*;

public  class StudentSqlProvider {
    public String updateByPrimaryKeySelective(Student record)
    {
        BEGIN();
        UPDATE("student");
        if(record.getName()!=null){
            SET("name=#{name,jdbcType=VARCHAR}");
        }
        if(record.getSex()>=0){
            SET("sex=#{sex,jdbcType=VARCHAR}");
        }
        if(record.getAge()>0){
            SET("age=#{age,jdbcType=INTEGER}");
        }
        WHERE("id=#{id,jdbcType=VARCHAR}");
        return SQL();
    }
}

示例中,首先通过UPDATE()方法生成Update语句,然后根据具体传入的参数动态拼接要更新的set字段,最后通过SQL()方法返回完整的SQL语句。


2. 调用updateByPrimaryKeySelective()方法

在provider中定义了updateByPrimaryKeySelective()方法后,就可以在mapper中引用该方法。

@UpdateProvider(type=StudentSqlProvider.class, method="updateByPrimaryKeySelective")
int updateByPrimaryKeySelective(Student record);

@UpdateProvider注解定义调用的自定义SQL方法,type参数定义动态生成SQL的类,method参数定义类中具体的方法名。

3. 验证测试

增加单元测试方法,验证是否生效。示例代码如下:

 @Test

public void testUpdateByPrimaryKeySelective()
 {
     Student student = new Student();   
     student.setId(1L);   
     student.setName("weiz动态修改");  
     studentMapper.updateByPrimaryKeySelective(student);   
     Student stu = studentMapper.selectById(1L);   
     System.out.println("name:"+stu.getName()+",age:"+stu.getAge()+",sex:"+ stu.getSex());
}

单击Run Test或在方法上右击,选择Run 'testUpdateByPrimaryKeySelective',根据输出结果可以看到只有name字段被修改,其他字段不受影响。说明通过@UpdateProvider动态生成Update语句验证成功。

二、分页查询

pageHelper是一款基于MyBatis的数据库分页插件,下面通过示例演示pageHelper实现分页查询。

1. 添加pageHelper依赖

修改pom.xml文件,添加pageHelper依赖:

<!-- pagehelper -->
<dependency>
 <groupId>com.github.pagehelper</groupId>   
 <artifactId>pagehelper-spring-boot-starter</artifactId>
</dependency>

2. 增加pageHelper配置

在application.properties中增加pageHelper配置。

    # 分页框架
    pagehelper.helperDialect=mysql
    pagehelper.reasonable=true
    pagehelper.supportMethodsArguments=true
    pagehelper.params=count=countSql

上面的示例是pageHelper分页框架的初始配置,主要用于指定数据库类型。
        •  helperDialect:指定数据库类型,可以不配置,pageHelper插件会自动检测数据库的类型。
  •  reasonable:分页合理化参数,默认为false,当该参数设置为true时,当pageNum≤0时,默认显示第一页,当pageNum超过pageSize时,显示最后一页。
•  supportMethodsArguments:分页插件会根据查询方法的参数,自动在params配置的字段中取值,找到合适的值会自动分页。
•  params:用于从对象中根据属性名取值,可以配置pageNum、pageSize,count不用配置映射的默认值。
3. 调用测试
增加单元测试方法,验证分页功能是否生效。示例代码如下:

@Test

public void testSelectListPaged() {  
     PageHelper.startPage(1, 5);  
     List<Student> students = studentMapper.selectAll();  
     PageInfo<Student> pageInfo = new PageInfo<Student>(students); 
     System.out.println("总页数:"+pageInfo.getPages()+",总条数:"+pageInfo.getTotal()+",当前        
     页:"+pageInfo.getPageNum());   
     
     for (Student stu : students)
     {                
        System.out.println("name:"+stu.getName()+",age:"+stu.getAge()); 
     }
}

        示例中,分页的核心只有一行代码,PageHelper.startPage(page,pageSize);就标识开始分页。添加此行代码之后,pageHelper插件会通过其内部的拦截器将执行的SQL语句转化为分页的SQL语句。

        单击Run Test或在方法上右击,选择Run 'testSelectListPaged',结果表明单元测试方法运行成功,控制台输出了当前页的数据列表、总页数、数据总条数和当前页。这说明使用pageHelper插件成功实现了分页功能。
        使用时PageHelper.startPage(pageNum, pageSize)一定要放在列表查询的方法中,这样在查询时会查出相应的数据量以及总数。

三、多数据源配置

        在Spring Boot项目中配置多数据源十分便捷。接下来介绍Spring Boot集成MyBatis实现多数据源的相关配置。

1. 配置数据源

在系统配置文件中配置多个数据源,即在application.properties文件中增加如下配置:

# MyBatis多数据源配置
# 数据库1的配置
spring.datasource.test1.driver-class-name = com.mysql.cj.jdbc.Driver
spring.datasource.test1.jdbc-url = jdbc:mysql://localhost:3306/MyBatis_test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
spring.datasource.test1.username = root
spring.datasource.test1.password = root
# 数据库2的配置
spring.datasource.test2.driver-class-name = com.mysql.cj.jdbc.Driver

spring.datasource.test2.jdbc-url = jdbc:mysql://localhost:3306/MyBatis2_test?   serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true

spring.datasource.test2.username = root
spring.datasource.test2.password = root

在上面的示例中,配置的是两个一样的数据库MyBatis_test和MyBatis2_test。连接数据库的配置使用的是jdbc-url,而不是之前的url,这一点需要注意。

2. 自定义数据源配置类

        1)在config包中创建DataSource1Config类,此类用于配置主数据源。示例代码如下:

@Configuration
@MapperScan(basePackages = "com.weiz.example01.mapper.test1"
          , sqlSessionFactoryRef = "test1SqlSessionFactory")
public class DataSource1Config {  
    @Bean(name = "test1DataSource")
    @ConfigurationProperties(prefix = "spring.datasource.test1")   
    @Primary    
    public DataSource testDataSource() {       
         return DataSourceBuilder.create().build();   
    } 
    
    @Bean(name = "test1SqlSessionFactory") 
    @Primary    
    public SqlSessionFactory testSqlSessionFactory(
        @Qualifier("test1DataSource") DataSource dataSource) 
        throws Exception {      
             SqlSessionFactoryBean bean = new SqlSessionFactoryBean();                
             bean.setDataSource(dataSource);
       
             return bean.getObject();    
    }  

     @Bean(name = "test1TransactionManager")   
     @Primary   
     public DataSourceTransactionManager testTransactionManager(
            @Qualifier("test1DataSource") DataSource dataSource) {               
       return new DataSourceTransactionManager(dataSource);
  
    } 

    @Bean(name = "test1SqlSessionTemplate")   
    @Primary
   
    public SqlSessionTemplate testSqlSessionTemplate(
          @Qualifier("test1SqlSessionFactory") SqlSessionFactory sqlSessionFactory)             
          throws Exception {       
              return new SqlSessionTemplate(sqlSessionFactory); 
    }
}

配置主数据源需要添加@Primary注解,其他普通数据源不能加这个注解,否则会报错。

2)在config包中创建DataSource2Config类,此类用于配置其他普通数据源。示例代码如下:

@Configuration
@MapperScan(basePackages = "com.weiz.example01.mapper.test2", 
            sqlSessionFactoryRef = "test2SqlSessionFactory")
public class DataSource2Config {   
     @Bean(name = "test2DataSource")  
     @ConfigurationProperties(prefix = "spring.datasource.test2")  
     public DataSource testDataSource() {       
         return DataSourceBuilder.create().build();  
     }  

    @Bean(name = "test2SqlSessionFactory")  
    public SqlSessionFactory testSqlSessionFactory(
           @Qualifier("test2DataSource") DataSource dataSource) 
           throws Exception {      
           SqlSessionFactoryBean bean = new SqlSessionFactoryBean();                    
           bean.setDataSource(dataSource);       
           return bean.getObject();   
    }   

        @Bean(name = "test2TransactionManager")   
        public DataSourceTransactionManager testTransactionManager(
        @Qualifier("test2DataSource") DataSource dataSource) {  
              return new DataSourceTransactionManager(dataSource); 
        } 

        @Bean(name = "test2SqlSessionTemplate") 
        public SqlSessionTemplate testSqlSessionTemplate(
        @Qualifier("test2SqlSessionFactory") SqlSessionFactory sqlSessionFactory) 
        throws Exception {      
              return new SqlSessionTemplate(sqlSessionFactory); 
        }
}

        DataSource2Config是普通数据源配置类。可以看到两个数据源都配置了各自的DataSource、SqlSessionFactory、TransactionManager和SqlSessionTemplate。两个数据源通过配置basePackages扫描mapper包路径,匹配对应的mapper包。配置时需要注意,配置错了不会出现异常,但是运行时会找错数据库。

3. 创建Mapper

创建com.weiz.example01.mapper.test1和com.weiz.example01.mapper.test2包,将之前的StudentMapper分别重命名为PrimaryStudentMapper和SecondaryStudentMapper并复制到相应的包中。

public interface PrimaryStudentMapper {
     @Select("select * from student")    
     List<Student> selectAll(); 

    @Insert({ "insert into student ("
               , "name, "
               , "age, "
               , "sex)"
               , "values ("
               , "#{name,jdbcType=VARCHAR},"
               , "#{age,jdbcType=INTEGER},"
               , "#{sex,jdbcType=INTEGER})" })
    int insert(Student record);
}


上面的示例为Primary数据库操作。SecondaryStudentMapper与PrimaryStudentMapper的代码基本一致。


4. 调用测试

增加单元测试方法,验证多数据源的操作是否生效。示例代码如下:

@Test
public void testMultiDataSource() {    
    // 新增    
    primaryStudentMapper.insert(new Student("weiz primary", 1, 30));                
    secondaryStudentMapper.insert(new Student("weiz secondary", 1, 30));    
    // 查询   
    System.out.println("primary 库:");  
    List<Student> studentsPrimary = primaryStudentMapper.selectAll();  

    for (Student stu : studentsPrimary){        
       System.out.println("name:"+stu.getName()+",age:"+stu.getAge());  }

    System.out.println("secondary 库:");   
    List<Student> studentsSecondary = primaryStudentMapper.selectAll();  

    for (Student stu : studentsSecondary){        
        System.out.println("name:"+stu.getName()+",age:"+stu.getAge());  }
}

        示例中,分别往两个数据库中写入学生信息数据,然后执行查询,从而验证多数据源操作是否生效。
        单击Run Test或在方法上右击,选择Run 'testMultiDataSource',查看单元测试结果,结果表明单元测试方法运行成功,通过控制台的输出可以看到,系统启动时创建了两个数据源连接,并且MyBatis_test和MyBatis2_test数据插入、查询都正常。这说明多数据源配置成功。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值