前端开发入门到精通的在线学习网站

网站首页 > 资源文章 正文

搭建SpringBoot+Mybatis框架环境(springboot 配置mybatis)

qiguaw 2024-09-26 16:37:08 资源文章 17 ℃ 0 评论

本文一共分三部分:SpringBoot+Mybatis环境搭建两种方式配置多数据源两种方式实现跨数据源事务,您可以直接跳到喜欢的部分,不过按顺序看完也不会花很多时间。。。

一、搭建SpringBoot+Mybatis框架环境

1、引入依赖

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.1</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

2、填写配置

spring:
  datasource:
    username: test
    password: test
    url: jdbc:mysql://jiubugaosuni.com:8888/test?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
    driver-class-name: com.mysql.cj.jdbc.Driver

3、建立mapper接口及配置Mybatis扫描包

package cn.zhh.mapper;
 
import cn.zhh.entity.Student;
 
/**
 * 学生Mapper
 *
 * @author Zhou Huanghua
 * @date 2019/10/25 23:09
 */
public interface StudentMapper {
 
    /**
     * 插入一条学生记录
     *
     * @param student 学生信息
     * @return 插入数量
     */
    int insert(Student student);
 
    /**
     * 根据id删除学生记录
     *
     * @param id 学生id
     * @return 删除数量
     */
    int deleteById(Long id);
}

4、Mapper.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="cn.zhh.mapper.StudentMapper">
 
    <resultMap id="BaseResultMap" type="cn.zhh.entity.Student">
        <result column="id" jdbcType="BIGINT" property="id"/>
        <result column="name" jdbcType="VARCHAR" property="name"/>
        <result column="code" jdbcType="VARCHAR" property="code"/>
        <result column="sex" jdbcType="TINYINT" property="sex"/>
        <result column="create_time" jdbcType="DATE" property="createTime"/>
        <result column="last_update_time" jdbcType="DATE" property="lastUpdateTime"/>
        <result column="is_deleted" jdbcType="TINYINT" property="isDeleted"/>
    </resultMap>
 
    <insert id="insert" parameterType="cn.zhh.entity.Student">
        INSERT INTO student (`name`, `code`, `sex`) VALUES (#{name, jdbcType=VARCHAR}, #{code, jdbcType=VARCHAR}, #{sex, jdbcType=TINYINT})
    </insert>
    <delete id="deleteById" parameterType="java.lang.Long">
        DELETE FROM student WHERE id = #{id, jdbcType=BIGINT}
    </delete>
</mapper>

二、两种方式配置多数据源

1、动态切换数据源

2、不同的mapper接口包使用不同的数据源

spring:
  datasource:
    username: test
    password: test
    url: jdbc:mysql://jiubugaosuni.com:8888/test?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
    driver-class-name: com.mysql.cj.jdbc.Driver
  datasource2:
      username: test2
      password: test2
      url: jdbc:mysql://biexiangzhidao.net:6666/test2?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
      driver-class-name: com.mysql.cj.jdbc.Driver
/**
 * 数据源配置
 *
 * @author Zhou Huanghua
 * @date 2019/10/26 0:24
 */
@Configuration
public class DataSourceConfig {
 
    @Bean
    @Primary
    public DataSource dataSource(@Value("${spring.datasource.username}") String username,
                                 @Value("${spring.datasource.password}") String password,
                                 @Value("${spring.datasource.url}") String url,
                                 @Value("${spring.datasource.driver-class-name}") String driverClassName) {
        return createDataSource(username, password, url, driverClassName);
    }
 
    @Bean
    public DataSource dataSource2(@Value("${spring.datasource2.username}") String username,
                                  @Value("${spring.datasource2.password}") String password,
                                  @Value("${spring.datasource2.url}") String url,
                                  @Value("${spring.datasource2.driver-class-name}") String driverClassName) {
        return createDataSource(username, password, url, driverClassName);
    }
 
    private DataSource createDataSource(String username, String password, String url, String driverClassName) {
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setJdbcUrl(url);
        dataSource.setDriverClassName(driverClassName);
        return dataSource;
    }
}
/**
 * MybatisConfig配置类
 *
 * @author Zhou Huanghua
 * @date 2019/10/26 0:31
 */
public class MybatisConfig {
 
    @Configuration
    @MapperScan(
            basePackages = "cn.zhh.mapper",
            sqlSessionTemplateRef = "sqlSessionTemplate")
    public static class Db1 {
 
        @Bean
        @Primary
        public SqlSessionFactory sqlSessionFactory(@Qualifier("dataSource") DataSource dataSource) throws Exception {
            SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
            factoryBean.setDataSource(dataSource);
            return factoryBean.getObject();
        }
 
        @Bean
        @Primary
        public SqlSessionTemplate sqlSessionTemplate(@Qualifier("sqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
            return new SqlSessionTemplate(sqlSessionFactory);
        }
 
        @Bean
        @Primary
        public DataSourceTransactionManager dataSourceTransactionManager(@Qualifier("dataSource") DataSource dataSource) {
            return new DataSourceTransactionManager(dataSource);
        }
    }
 
    @Configuration
    @MapperScan(
            basePackages = "cn.zhh.mapper2",
            sqlSessionTemplateRef = "sqlSessionTemplate2")
    public static class Db2 {
 
        @Bean
        public SqlSessionFactory sqlSessionFactory2(@Qualifier("dataSource2") DataSource dataSource) throws Exception {
            SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
            factoryBean.setDataSource(dataSource);
            return factoryBean.getObject();
        }
 
        @Bean
        public SqlSessionTemplate sqlSessionTemplate2(@Qualifier("sqlSessionFactory2") SqlSessionFactory sqlSessionFactory) throws Exception {
            return new SqlSessionTemplate(sqlSessionFactory);
        }
 
        @Bean
        public DataSourceTransactionManager dataSourceTransactionManager2(@Qualifier("dataSource2") DataSource dataSource) {
            return new DataSourceTransactionManager(dataSource);
        }
    }
}

三、两种方式实现跨数据源事务

1、atomikos

2、注解+切面 = 自己实现

/**
 * 多数据源事务注解
 *
 * @author Zhou Huanghua
 * @date 2019/10/26 1:16
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MultiDataSourceTransactional {
 
    /**
     * 事务管理器数组
     */
    String[] transactionManagers();
}





/**
 * 多数据源事务切面
 * ※采用Around似乎不行※
 *
 * @author Zhou Huanghua
 * @date 2019/10/26 1:16
 */
@Component
@Aspect
public class MultiDataSourceTransactionAspect {
 
    /**
     * 线程本地变量:为什么使用栈?※为了达到后进先出的效果※
     */
    private static final ThreadLocal<Stack<Pair<DataSourceTransactionManager, TransactionStatus>>> THREAD_LOCAL = new ThreadLocal<>();
 
    /**
     * 用于获取事务管理器
     */
    @Autowired
    private ApplicationContext applicationContext;
 
    /**
     * 事务声明
     */
    private DefaultTransactionDefinition def = new DefaultTransactionDefinition();
    {
        // 非只读模式
        def.setReadOnly(false);
        // 事务隔离级别:采用数据库的
        def.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);
        // 事务传播行为
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
    }
 
    /**
     * 切面
     */
    @Pointcut("@annotation(cn.zhh.annotation.MultiDataSourceTransactional)")
    public void pointcut() {
    }
 
    /**
     * 声明事务
     *
     * @param transactional 注解
     */
    @Before("pointcut() && @annotation(transactional)")
    public void before(MultiDataSourceTransactional transactional) {
        // 根据设置的事务名称按顺序声明,并放到ThreadLocal里
        String[] transactionManagerNames = transactional.transactionManagers();
        Stack<Pair<DataSourceTransactionManager, TransactionStatus>> pairStack = new Stack<>();
        for (String transactionManagerName : transactionManagerNames) {
            DataSourceTransactionManager transactionManager = applicationContext.getBean(transactionManagerName, DataSourceTransactionManager.class);
            TransactionStatus transactionStatus = transactionManager.getTransaction(def);
            pairStack.push(new Pair(transactionManager, transactionStatus));
        }
        THREAD_LOCAL.set(pairStack);
    }
 
    /**
     * 提交事务
     */
    @AfterReturning("pointcut()")
    public void afterReturning() {
        // ※栈顶弹出(后进先出)
        Stack<Pair<DataSourceTransactionManager, TransactionStatus>> pairStack = THREAD_LOCAL.get();
        while (!pairStack.empty()) {
            Pair<DataSourceTransactionManager, TransactionStatus> pair = pairStack.pop();
            pair.getKey().commit(pair.getValue());
        }
        THREAD_LOCAL.remove();
    }
 
    /**
     * 回滚事务
     */
    @AfterThrowing(value = "pointcut()")
    public void afterThrowing() {
        // ※栈顶弹出(后进先出)
        Stack<Pair<DataSourceTransactionManager, TransactionStatus>> pairStack = THREAD_LOCAL.get();
        while (!pairStack.empty()) {
            Pair<DataSourceTransactionManager, TransactionStatus> pair = pairStack.pop();
            pair.getKey().rollback(pair.getValue());
        }
        THREAD_LOCAL.remove();
    }
}




Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表