• spring-boot mybatis 配置 主从分离 事务


    首先是spring-boot的配置 web.xml  

    <!DOCTYPE web-app PUBLIC
     "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
     "http://java.sun.com/dtd/web-app_2_3.dtd" >
    
    <web-app xmlns="http://java.sun.com/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
    		  http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
             version="3.0">
    
      <display-name>Archetype Created Web Application</display-name>
      <context-param>
        <param-name>spring.config.name</param-name>
        <param-value>cpp</param-value>
      </context-param>
      <context-param>
        <param-name>spring.config.path</param-name>
        <param-value>classpath:config/</param-value>
      </context-param>
      <context-param>
        <param-name>spring.profiles.active</param-name>
        <param-value>pro</param-value>
      </context-param>
      <context-param>
        <param-name>logging.config</param-name>
        <param-value>classpath:logbackConfig/logback-me-dev.xml</param-value>
      </context-param>
    </web-app>

    也可以不采用web.xml,直接在Application.java指向 cpp-pro.yml  (baseConfig,MvcConfig,SwaggerConfig,Redisconfig,HttpSessionConfig为其它config配置 跟本文无关) :

    @SpringBootApplication
    //@EnableAutoConfiguration
    @EnableScheduling
    public class Application extends SpringBootServletInitializer {
    
    	
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		//SpringApplication.run(Application.class, args);
    		//System.out.println("classpath:/config/app-dev.yml");
    
    		new SpringApplicationBuilder(BaseConfig.class,
    				MvcConfig.class,
    				SwaggerConfig.class,
    				RedisConfig.class,
    				HttpSessionConfig.class,
                       MyBatisConfig.class ).properties("spring.config.location=classpath:config/cpp-dev.yml").run(args); } }

      

    cpp-pro.yml文件如下:

    spring:
        redis:
            host: 127.0.0.1
            port: 6379
            timeout: 0
            pool:
              max-active: -1  #最大连接数
              max-idle: -1   #最大空闲数
              min-idle: 0     #最小空闲数
              max-wait: -1    #连接池耗尽时,新获取连接需要等待的最大时间
        freemarker:
            allow-request-override: false
            cache: true
            check-template-location: true
            charset: UTF-8
            content-type: text/html
            expose-request-attributes: false
            expose-session-attributes: false
            expose-spring-macro-helpers: false
            prefix:
            #suffix: .ftl
            suffix: .html
            template-loader-path: /freemarker/
            #request-context-attribute
            #settings.*
            #view-names:  # whitelist of view names that can be resolved
        datasource:
            driverClassName: com.mysql.jdbc.Driver
            url: jdbc:mysql://127.0.0.1:3306/me?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf8&autoReconnect=true&rewriteBatchedStatements=true&useSSL=false
            username: root
            password: huhanbo
            dsslave:
              driverClassName: com.mysql.jdbc.Driver
              url: jdbc:mysql://127.0.0.1:3306/me?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf8&autoReconnect=true&rewriteBatchedStatements=true&useSSL=false
              username: root
              password: huhanbo


    mybatis:
    typeAliasesPackage: com.me.mybatis.entity
    mapperLocations: classpath:mybatisMapper/*.xml
     

    另外 pom.xml的新加如下依赖 

    <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>1.3.0</version>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.39</version>
            </dependency>
    
            <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.2</version>
            </dependency>

     书写spring config文件:

    package configuration;
    
    import java.sql.SQLException;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.Properties;
    
    import javax.annotation.Resource;
    import javax.sql.DataSource;
    
    import com.me.common.datasource.DatabaseType;
    import com.me.common.datasource.DynamicDataSource;
    import org.apache.ibatis.mapping.DatabaseIdProvider;
    import org.apache.ibatis.plugin.Interceptor;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.mybatis.spring.SqlSessionFactoryBean;
    import org.mybatis.spring.annotation.MapperScan;
    import org.mybatis.spring.boot.autoconfigure.ConfigurationCustomizer;
    import org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration;
    import org.mybatis.spring.boot.autoconfigure.MybatisProperties;
    import org.springframework.beans.factory.ObjectProvider;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
    import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
    import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.context.annotation.PropertySource;
    import org.springframework.core.io.ResourceLoader;
    import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
    import org.springframework.jdbc.datasource.DataSourceTransactionManager;
    import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
    import org.springframework.transaction.PlatformTransactionManager;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
    import com.alibaba.druid.pool.DruidDataSourceFactory;
    
    
    import com.me.property.JdbcProperties;
    
    @Configuration
    @MapperScan(basePackages="com.me.mybatis.persistence")
    @EnableTransactionManagement
    public class MyBatisConfig {
    
        @Value("${mybatis.mapperLocations}")
        private String mapperLocations;
        
        @Value("${mybatis.typeAliasesPackage}")
        private String typeAliasesPackage;
        
        @Autowired
        private JdbcProperties jdbcProperties;
    
    
        @Bean
        @Primary
        public DataSource masterDataSource() throws Exception {
    
            Properties props = new Properties();
                     props.put("driverClassName", jdbcProperties.getDriverClassName());
                     props.put("url", jdbcProperties.getUrl());
                    props.put("username", jdbcProperties.getUsername());
                    props.put("password", jdbcProperties.getPassword());
                    return DruidDataSourceFactory.createDataSource(props);
    //        return DataSourceBuilder.create(Thread.currentThread().getContextClassLoader())
    //                .driverClassName(jdbcProperties.getDriverClassName()).url(jdbcProperties.getUrl())
    //                .username(jdbcProperties.getUsername()).password(jdbcProperties.getPassword()).build();
        }
    
    
        @Bean()
        public DataSource slaveDataSource() throws Exception {
            Properties props = new Properties();
            props.put("driverClassName", jdbcProperties.getDsslave().getDriverClassName());
            props.put("url", jdbcProperties.getDsslave().getUrl());
            props.put("username", jdbcProperties.getDsslave().getUsername());
            props.put("password", jdbcProperties.getDsslave().getPassword());
            return DruidDataSourceFactory.createDataSource(props);
        }
    
    
        /**
         * @Primary 该注解表示在同一个接口有多个实现类可以注入的时候,默认选择哪一个,而不是让@autowire注解报错
         *
         *
         */
        @Bean
        public DynamicDataSource dataSource(@Qualifier("masterDataSource") DataSource masterDataSource,
                  @Qualifier("slaveDataSource") DataSource slaveDataSource) {
            Map<Object, Object> targetDataSources = new HashMap<>();
            targetDataSources.put(DatabaseType.masterDatasource, masterDataSource);
            targetDataSources.put(DatabaseType.slaveDatasource, slaveDataSource);
    
            DynamicDataSource dataSource = new DynamicDataSource();
            dataSource.setTargetDataSources(targetDataSources);// 该方法是AbstractRoutingDataSource的方法
            dataSource.setDefaultTargetDataSource(masterDataSource);// 默认的datasource设置为myTestDbDataSource
            return dataSource;
        }
    
        /**
         * 配置事务管理器
         */
        @Bean
        public DataSourceTransactionManager transactionManager(DynamicDataSource dataSource) throws Exception {
            return new DataSourceTransactionManager(dataSource);
        }
    
        @Bean
        public SqlSessionFactory createSqlSessionFactory(DynamicDataSource  dataSource) throws Exception {
            SqlSessionFactoryBean fb = new SqlSessionFactoryBean();
            fb.setDataSource(dataSource);
            fb.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(mapperLocations));
            fb.setTypeAliasesPackage(typeAliasesPackage);
            return fb.getObject();
        }
    }

    使用web.xml指向cpp-pro.xml的startup class如下 (baseConfig,MvcConfig,SwaggerConfig,Redisconfig,HttpSessionConfig为其它config配置 跟本文无关)  :

    package startup;
    
    import configuration.*;
    import org.springframework.boot.Banner.Mode;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
    import org.springframework.boot.builder.SpringApplicationBuilder;
    import org.springframework.boot.web.support.SpringBootServletInitializer;
    
    //@SpringBootApplication
    //@EnableAutoConfiguration
    public class Application extends SpringBootServletInitializer {
    
        @Override
        protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
            builder.sources(BaseConfig.class,
                    MyBatisConfig.class,
                    MvcConfig.class,
                    WebSocketConfig.class,
                    FastDfsConfig.class);
            return builder;
        }
        
        public static void main(String[] args) {
            // TODO Auto-generated method stub
    //        SpringApplication.run(Application.class, args);
    
            SpringApplication app =new SpringApplicationBuilder(BaseConfig.class,
    				MvcConfig.class,
    				SwaggerConfig.class,
    				RedisConfig.class,
    				HttpSessionConfig.class,
               MyBatisConfig.class);
    
       app.setBannerMode(Mode.CONSOLE); 
       app.run(args);
        } 
    }
    

      

    事务在需要地方使用 @Transactional 即可

    配置只读:

    package com.me.common.datasource;
    
    
    /**
      * 作用:
      * 1、保存一个线程安全的DatabaseType容器
      */
    public class DatabaseContextHolder {
        private static final ThreadLocal<DatabaseType> contextHolder = new ThreadLocal<>();
                 public static void setDatabaseType(DatabaseType type){
                    contextHolder.set(type);
                 }
    
                public static void clearDatabaseType(){
                    contextHolder.remove();
                }
    
                 public static DatabaseType getDatabaseType(){
                    return contextHolder.get();
                }
    }
    package com.me.common.datasource;
    
    public enum DatabaseType {
        masterDatasource,slaveDatasource
    }
    package com.me.common.datasource;
    
    import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
    
    public class DynamicDataSource extends AbstractRoutingDataSource {
    
        protected Object determineCurrentLookupKey() {
                    return DatabaseContextHolder.getDatabaseType();
        }
    }
    package com.me.common.datasource;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ReadOnlyConnection {
    }
    package com.me.common.datasource;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.core.Ordered;
    import org.springframework.stereotype.Component;
    
    @Aspect
    @Component
    public class ReadOnlyConnectionInterceptor implements Ordered {
    
        private static final Logger logger = LoggerFactory.getLogger(ReadOnlyConnectionInterceptor.class);
    
        @Around("@annotation(readOnlyConnection)")
        public Object proceed(ProceedingJoinPoint proceedingJoinPoint, ReadOnlyConnection readOnlyConnection) throws Throwable {
            try {
                logger.info("set database connection to read only");
                DatabaseContextHolder.setDatabaseType(DatabaseType.slaveDatasource);
                Object result = proceedingJoinPoint.proceed();
                return result;
            } finally {
                DatabaseContextHolder.clearDatabaseType();
                logger.info("restore database connection");
            }
        }
    
        @Override
        public int getOrder() {
            return 0;
        }
    }
     
    参考:
    http://www.jb51.net/article/107706.htm
    http://www.cnblogs.com/java-zhao/p/5413845.html
     
  • 相关阅读:
    C#验证类(使用正则表达式)
    SQL数据库还原语句
    JS键盘或鼠标事件
    列表针对列宽度自动调整显示内容,超长以...缩写结尾
    SQL按照日、周、月、年统计数据 (转自BLEACH的blog)
    SQL利用Case When Then多条件判断
    调用Web服务:请求因HTTP状态401失败:Unauthorized
    IFrame自动适应宽高,去掉空白
    Asp调用WebService事例
    Timer不执行Elapsed事件的解决办法
  • 原文地址:https://www.cnblogs.com/huhanbo/p/7536636.html
Copyright © 2020-2023  润新知