├── .gitignore ├── LICENSE ├── README.md ├── create_db.sql ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── lishuangqi │ │ ├── BigServerApplication.java │ │ ├── annotation │ │ └── DataSource.java │ │ ├── config │ │ ├── MybatisPlusConfig.java │ │ └── ThreadConfig.java │ │ ├── constant │ │ ├── CommonConstants.java │ │ └── SecurityConstants.java │ │ ├── controller │ │ └── TestController.java │ │ ├── datasources │ │ ├── DataSourceNames.java │ │ ├── DynamicDataSource.java │ │ ├── DynamicDataSourceConfig.java │ │ ├── MultiDataSourceTransaction.java │ │ ├── MultiDataSourceTransactionFactory.java │ │ └── aspect │ │ │ └── DataSourceAspect.java │ │ ├── db1 │ │ ├── dao │ │ │ └── UserDao.java │ │ ├── entity │ │ │ └── UserEntity.java │ │ ├── package-info.java │ │ └── service │ │ │ ├── UserService.java │ │ │ └── impl │ │ │ └── UserServiceImpl.java │ │ ├── db2 │ │ ├── dao │ │ │ └── UserBakDao.java │ │ ├── entity │ │ │ └── UserBakEntity.java │ │ └── service │ │ │ ├── UserBakService.java │ │ │ └── impl │ │ │ └── UserBakServiceImpl.java │ │ └── utils │ │ ├── PageQuery.java │ │ ├── PageUtils.java │ │ ├── R.java │ │ ├── RRException.java │ │ ├── SQLFilter.java │ │ └── UuidUtil.java └── resources │ ├── application.yml │ ├── bootstrap.properties │ ├── mapper │ ├── db1 │ │ └── UserDao.xml │ └── db2 │ │ └── UserBakDao.xml │ └── sql │ └── user.sql └── test └── java └── com └── lishuangqi └── BigServerApplicationTests.java /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | /target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | 20 | ### NetBeans ### 21 | /nbproject/private/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ 26 | /build/ 27 | 28 | ### VS Code ### 29 | .vscode/ 30 | *.lck 31 | *.log 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2006 by Rob Landley 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any purpose 4 | with or without fee is hereby granted. 5 | 6 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 7 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 8 | AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 9 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 10 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 11 | OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 12 | PERFORMANCE OF THIS SOFTWARE. 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # springboot-mybatis-druid-atomikos 2 | mybatis-plus支持AOP动态数据源切换,atomikos分布式事务 3 | 4 | 一、 项目说明 5 | 本用例基于springboot+mybatis+druid+atomikos 配置动态多数据源, 实现分布式事务。 6 | 源码仓库地址: https://github.com/lishuangqi/springboot-mybatis-druid-atomikos 7 | 8 | 根据网上的搭建始终没实现atomikos分布式事务,经过两天网上查询资料终于实现了。刚开始分布式事务加入后,多数据源切换不能用了,一个线程内执行了第一个数据源service后,第二数据service不触发动态切换数据源(http://localhost:8101/testTrans)。单独访问第二数据源方法又是可以切换的(http://localhost:8101/testTrans1,http://localhost:8101/testTrans2)。 9 | 10 | 经查找 springboot+mybatis解决多数据源切换事务控制不生效的问题https://blog.csdn.net/gaoshili001/article/details/79378902 11 | springboot的生命式事务需要重写Transaction,就能切换数据源了。 12 | 13 | 原因:查看源代码中DataSourceTransactionManager这个类 14 | 15 |        当我们配置了事物管理器和拦截Service中的方法后,每次执行Service中方法前会开启一个事务,并且同时会缓存一些东西:DataSource、SqlSessionFactory、Connection等,所以,我们在外面再怎么设置要求切换数据源也没用,因为Conneciton都是从缓存中拿的,所以我们要想能够顺利的切换数据源,实际就是能够动态的根据DatabaseType获取不同的Connection,并且要求不能影响整个事物的特性。 16 | 17 | JTA(Java Transaction API):是J2EE的编程接口规范,它是XA协议的JAVA实现。它主要定义了: 18 | 19 | 一个事务管理器的接口javax.transaction.TransactionManager,定义了有关事务的开始、提交、撤回等>操作。 20 | 一个满足XA规范的资源定义接口javax.transaction.xa.XAResource,一种资源如果要支持JTA事务,就需要让它的资源实现该XAResource接口,并实现该接口定义的两阶段提交相关的接口。 21 | 如果我们有一个应用,它使用JTA接口实现事务,应用在运行的时候,就需要一个实现JTA的容器,一般情况下,这是一个J2EE容器,像JBoss,Websphere等应用服务器。但是,也有一些独立的框架实现了JTA,例如Atomikos, bitronix都提供了jar包方式的JTA实现框架。这样我们就能够在Tomcat或者Jetty之类的服务器上运行使用JTA实现事务的应用系统。 22 | 在上面的本地事务和外部事务的区别中说到,JTA事务是外部事务,可以用来实现对多个资源的事务性。它正是通过每个资源实现的XAResource来进行两阶段提交的控制。感兴趣的同学可以看看这个接口的方法,除了commit, rollback等方法以外,还有end(), forget(), isSameRM(), prepare()等等。光从这些接口就能够想象JTA在实现两阶段事务的复杂性。 23 | Atomikos事务管理器: Atomikos是一个非常流行的开源事务管理器,并且可以嵌入到Spring Boot应用中。可以使用 spring-boot-starter-jta-atomikos Starter去获取正确的Atomikos库。Spring Boot会自动配置Atomikos,并将合适的 depends-on 应用到Spring Beans上,确保它们以正确的顺序启动和关闭。 24 | 25 |   26 | 二、动态多数据源,分布事务 27 | 这里我们创建druid数据源的时候,创建的是DruidXADataSource,它继承自DruidDataSource并支持XA分布式事务; 28 | 使用 AtomikosDataSourceBean 包装我们创建的DruidXADataSource,使得数据源能够被 JTA 事务管理器管理; 29 | --------------------- 30 | 作者:nicklsq 31 | 来源:CSDN 32 | 原文:https://blog.csdn.net/nicklsq/article/details/90286726 33 | 版权声明:本文为博主原创文章,转载请附上博文链接! 34 | 35 | ##问题1 接入分布式事务后,动态数据源不能切换 36 | DataSource必须切换为XADataSource,连接池环卫DruidXADataSource 37 | @Primary 38 | @Bean(name = "bigdataDataSource") 39 | public DataSource bigdataDataSource(Environment env) { 40 | String sourceName = "bigdata"; 41 | Properties prop = build(env, basePackage+sourceName+"."); 42 | AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean(); 43 | xaDataSource.setXaDataSourceClassName(xaDataSourceClassName); 44 | xaDataSource.setUniqueResourceName(sourceName); 45 | xaDataSource.setPoolSize(5); 46 | xaDataSource.setXaProperties(prop); 47 | } 48 | ##问题3 重写sqlSessionFactory 49 | SqlSessionFactoryBean 修改 MybatisSqlSessionFactoryBean,mybatis才能正常启动 50 | 51 | 52 | ##问题4 接入分布式事务后,动态数据源不能切换 53 | 当我们配置了事物管理器和拦截Service中的方法后,每次执行Service中方法前会开启一个事务, 54 | 并且同时会缓存一些东西:DataSource、SqlSessionFactory、Connection等, 55 | 所以,我们在外面再怎么设置要求切换数据源也没用,因为Conneciton都是从缓存中拿的, 56 | 所以我们要想能够顺利的切换数据源,实际就是能够动态的根据DatabaseType获取不同的Connection, 57 | 并且要求不能影响整个事物的特性。 58 | 重写Transaction,注入到mybatis里sqlSessionFactory, bean.setTransactionFactory(new MultiDataSourceTransactionFactory()); 59 | MultiDataSourceTransaction.java 60 | MultiDataSourceTransactionFactory.java 61 | @Primary 62 | @Bean(name = "sqlSessionFactory") 63 | public SqlSessionFactory testSqlSessionFactory(@Qualifier("dynamicDataSource") DataSource dataSource) 64 | throws Exception { 65 | MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean(); 66 | bean.setDataSource(dataSource); 67 | bean.setTransactionFactory(new MultiDataSourceTransactionFactory()); 68 | return bean.getObject(); 69 | } -------------------------------------------------------------------------------- /create_db.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE if not exists bigdata charset utf8; 2 | use bigdata; 3 | create table if not exists interface_info 4 | ( 5 | id varchar(32) not null comment 'id' 6 | primary key, 7 | server_id int null, 8 | server_url varchar(128) null comment '服务器id', 9 | interface_code varchar(64) null comment '编码code' 10 | 11 | ); 12 | 13 | CREATE DATABASE if not exists plat charset utf8; 14 | use plat; 15 | create table if not exists t_sys_user 16 | ( 17 | ID varchar(64) not null comment 'ID' 18 | primary key, 19 | DEPT_ID varchar(64) null comment 'ID', 20 | LOGIN_NAME varchar(64) not null comment '登录帐号', 21 | PASSWD varchar(64) not null comment '登录密码', 22 | USER_NAME varchar(64) not null comment '用户名称' 23 | ) -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.lishuangqi 7 | springboot-mybatis-druid-atomikos 8 | 1.0 9 | ${project.artifactId} 10 | jar 11 | Demo project for Spring Boot 12 | 13 | 14 | org.springframework.boot 15 | spring-boot-starter-parent 16 | 2.1.4.RELEASE 17 | 18 | 19 | 20 | 21 | 3.1.0 22 | 1.1.10 23 | 1.2.33 24 | 6.0.6 25 | 26 | 27 | 28 | 29 | 30 | javax.servlet 31 | javax.servlet-api 32 | 33 | 34 | 35 | org.springframework.boot 36 | spring-boot-starter-aop 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-starter-jta-atomikos 41 | 42 | 43 | 44 | org.springframework.boot 45 | spring-boot-starter-web 46 | 47 | 48 | 49 | 50 | com.baomidou 51 | mybatis-plus-boot-starter 52 | ${mybatis-plus.version} 53 | 54 | 55 | 56 | mysql 57 | mysql-connector-java 58 | ${mysql.version} 59 | 60 | 61 | 62 | com.oracle 63 | ojdbc6 64 | 12.1.0.1-atlassian-hosted 65 | 66 | 67 | 68 | com.alibaba 69 | druid-spring-boot-starter 70 | ${druid.version} 71 | 72 | 73 | 74 | com.alibaba 75 | fastjson 76 | ${fastjson.version} 77 | 78 | 79 | 80 | org.projectlombok 81 | lombok 82 | true 83 | 84 | 85 | org.apache.commons 86 | commons-lang3 87 | 88 | 89 | org.springframework.boot 90 | spring-boot-starter-test 91 | test 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | org.springframework.boot 101 | spring-boot-maven-plugin 102 | 103 | 104 | com.spotify 105 | docker-maven-plugin 106 | 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /src/main/java/com/lishuangqi/BigServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.lishuangqi; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.boot.builder.SpringApplicationBuilder; 6 | import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; 7 | import org.springframework.context.annotation.Configuration; 8 | 9 | @SpringBootApplication 10 | @Configuration 11 | public class BigServerApplication extends SpringBootServletInitializer { 12 | 13 | public static void main(String[] args) { 14 | SpringApplication.run(BigServerApplication.class, args); 15 | } 16 | 17 | /** 18 | * 若打包成war包,则需要继承 SpringBootServletInitializer类, 19 | * 覆盖其config(SpringApplicationBuilder)方法 20 | * @param application 21 | * @return 22 | */ 23 | @Override 24 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 25 | return application.sources(BigServerApplication.class); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/lishuangqi/annotation/DataSource.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 人人开源 All rights reserved. 3 | * 4 | * https://www.renren.io 5 | * 6 | * 版权所有,侵权必究! 7 | */ 8 | 9 | package com.lishuangqi.annotation; 10 | 11 | import java.lang.annotation.*; 12 | 13 | /** 14 | * 多数据源注解 15 | * 16 | * @author Mark sunlightcs@gmail.com 17 | * @since 1.0.0 18 | */ 19 | @Target({ElementType.METHOD, ElementType.TYPE}) 20 | @Retention(RetentionPolicy.RUNTIME) 21 | @Documented 22 | @Inherited 23 | public @interface DataSource { 24 | String name() default ""; 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/lishuangqi/config/MybatisPlusConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2020, 冷冷 (wangiegie@gmail.com). 3 | *

4 | * Licensed under the GNU Lesser General Public License 3.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * https://www.gnu.org/licenses/lgpl.html 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lishuangqi.config; 18 | 19 | import com.baomidou.mybatisplus.core.injector.ISqlInjector; 20 | import com.baomidou.mybatisplus.extension.injector.LogicSqlInjector; 21 | import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; 22 | import org.mybatis.spring.annotation.MapperScan; 23 | import org.springframework.context.annotation.Bean; 24 | import org.springframework.context.annotation.Configuration; 25 | import org.springframework.transaction.annotation.EnableTransactionManagement; 26 | 27 | /** 28 | * @author lengleng 29 | * @date 2019/2/1 30 | */ 31 | @Configuration 32 | @EnableTransactionManagement 33 | @MapperScan("com.lishuangqi.**.dao*") 34 | public class MybatisPlusConfig { 35 | /** 36 | * 分页插件 37 | * 38 | * @return PaginationInterceptor 39 | */ 40 | @Bean 41 | public PaginationInterceptor paginationInterceptor() { 42 | return new PaginationInterceptor(); 43 | } 44 | 45 | /** 46 | * 数据权限插件 47 | * 48 | * @return DataScopeInterceptor 49 | */ 50 | // @Bean 51 | // public DataScopeInterceptor dataScopeInterceptor() { 52 | // return new DataScopeInterceptor(); 53 | // } 54 | 55 | /** 56 | * 逻辑删除 57 | * 58 | * @return 59 | */ 60 | @Bean 61 | public ISqlInjector sqlInjector() { 62 | return new LogicSqlInjector(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/lishuangqi/config/ThreadConfig.java: -------------------------------------------------------------------------------- 1 | package com.lishuangqi.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.scheduling.annotation.EnableAsync; 6 | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; 7 | 8 | import java.util.concurrent.Executor; 9 | 10 | /** 11 | * Created by michael on 2019/4/24. 12 | */ 13 | 14 | @Configuration 15 | @EnableAsync // 启用异步任务 16 | public class ThreadConfig { 17 | 18 | 19 | // 这里是声明一个bean,类似于xml中的标签。 20 | // Executor 就是一个线程池 21 | @Bean 22 | public Executor getExecutor() { 23 | ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); 24 | executor.setCorePoolSize(5); 25 | executor.setMaxPoolSize(10); 26 | executor.setQueueCapacity(25); 27 | executor.initialize(); 28 | return executor; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/lishuangqi/constant/CommonConstants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2020, 冷冷 (wangiegie@gmail.com). 3 | *

4 | * Licensed under the GNU Lesser General Public License 3.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * https://www.gnu.org/licenses/lgpl.html 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lishuangqi.constant; 18 | 19 | /** 20 | * @author lengleng 21 | * @date 2019/2/1 22 | */ 23 | public interface CommonConstants { 24 | /** 25 | * 删除 26 | */ 27 | String STATUS_DEL = "1"; 28 | /** 29 | * 正常 30 | */ 31 | String STATUS_NORMAL = "0"; 32 | 33 | /** 34 | * 锁定 35 | */ 36 | String STATUS_LOCK = "9"; 37 | 38 | /** 39 | * 菜单 40 | */ 41 | String MENU = "0"; 42 | 43 | /** 44 | * 编码 45 | */ 46 | String UTF8 = "UTF-8"; 47 | 48 | /** 49 | * JSON 资源 50 | */ 51 | String CONTENT_TYPE = "application/json; charset=utf-8"; 52 | 53 | /** 54 | * 前端工程名 55 | */ 56 | String FRONT_END_PROJECT = "pig-ui"; 57 | 58 | /** 59 | * 后端工程名 60 | */ 61 | String BACK_END_PROJECT = "pig"; 62 | 63 | /** 64 | * 成功标记 65 | */ 66 | Integer SUCCESS = 0; 67 | /** 68 | * 失败标记 69 | */ 70 | Integer FAIL = 1; 71 | 72 | /** 73 | * 验证码前缀 74 | */ 75 | String DEFAULT_CODE_KEY = "DEFAULT_CODE_KEY_"; 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/com/lishuangqi/constant/SecurityConstants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2020, 冷冷 (wangiegie@gmail.com). 3 | *

4 | * Licensed under the GNU Lesser General Public License 3.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * https://www.gnu.org/licenses/lgpl.html 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lishuangqi.constant; 18 | 19 | /** 20 | * @author lengleng 21 | * @date 2019/2/1 22 | */ 23 | public interface SecurityConstants { 24 | /** 25 | * 角色前缀 26 | */ 27 | String ROLE = "ROLE_"; 28 | /** 29 | * 前缀 30 | */ 31 | String PROJECT_PREFIX = "pig_"; 32 | 33 | /** 34 | * oauth 相关前缀 35 | */ 36 | String OAUTH_PREFIX = "oauth:"; 37 | /** 38 | * 项目的license 39 | */ 40 | String PROJECT_LICENSE = "made by pig"; 41 | 42 | /** 43 | * 内部 44 | */ 45 | String FROM_IN = "Y"; 46 | 47 | /** 48 | * 标志 49 | */ 50 | String FROM = "from"; 51 | 52 | /** 53 | * 手机号登录URL 54 | */ 55 | String MOBILE_TOKEN_URL = "/mobile/token"; 56 | 57 | /** 58 | * 默认登录URL 59 | */ 60 | String OAUTH_TOKEN_URL = "/oauth/token"; 61 | 62 | /** 63 | * grant_type 64 | */ 65 | String REFRESH_TOKEN = "refresh_token"; 66 | 67 | /** 68 | * oauth 客户端信息 69 | */ 70 | String CLIENT_DETAILS_KEY = PROJECT_PREFIX + OAUTH_PREFIX + "client:details"; 71 | 72 | /** 73 | * {bcrypt} 加密的特征码 74 | */ 75 | String BCRYPT = "{bcrypt}"; 76 | /** 77 | * sys_oauth_client_details 表的字段,不包括client_id、client_secret 78 | */ 79 | String CLIENT_FIELDS = "client_id, CONCAT('{noop}',client_secret) as client_secret, resource_ids, scope, " 80 | + "authorized_grant_types, web_server_redirect_uri, authorities, access_token_validity, " 81 | + "refresh_token_validity, additional_information, autoapprove"; 82 | 83 | /** 84 | * JdbcClientDetailsService 查询语句 85 | */ 86 | String BASE_FIND_STATEMENT = "select " + CLIENT_FIELDS 87 | + " from sys_oauth_client_details"; 88 | 89 | /** 90 | * 默认的查询语句 91 | */ 92 | String DEFAULT_FIND_STATEMENT = BASE_FIND_STATEMENT + " order by client_id"; 93 | 94 | /** 95 | * 按条件client_id 查询 96 | */ 97 | String DEFAULT_SELECT_STATEMENT = BASE_FIND_STATEMENT + " where client_id = ?"; 98 | 99 | /*** 100 | * 资源服务器默认bean名称 101 | */ 102 | String RESOURCE_SERVER_CONFIGURER = "resourceServerConfigurerAdapter"; 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/com/lishuangqi/controller/TestController.java: -------------------------------------------------------------------------------- 1 | package com.lishuangqi.controller; 2 | 3 | import com.lishuangqi.db2.entity.UserBakEntity; 4 | import com.lishuangqi.db2.service.UserBakService; 5 | import com.lishuangqi.db1.entity.UserEntity; 6 | import com.lishuangqi.db1.service.UserService; 7 | import com.lishuangqi.utils.UuidUtil; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.transaction.annotation.Transactional; 11 | import org.springframework.web.bind.annotation.GetMapping; 12 | import org.springframework.web.bind.annotation.RestController; 13 | 14 | import java.util.List; 15 | 16 | /** 17 | * 多文件加载的例子使用的验证接口 18 | *

19 | * blog: http://blog.didispace.com/spring-cloud-alibaba-nacos-config-3/ 20 | */ 21 | @Slf4j 22 | @RestController 23 | public class TestController { 24 | 25 | 26 | 27 | @Autowired 28 | UserService userService; 29 | @Autowired 30 | UserBakService userBakService; 31 | 32 | 33 | @GetMapping("/testTrans") 34 | @Transactional 35 | public String testTrans() { 36 | UserEntity userEntity = new UserEntity(); 37 | userEntity.setId(UuidUtil.generateUUID()); 38 | userEntity.setUserName("test0"); 39 | userEntity.setLoginName("test0"); 40 | userEntity.setPasswd("test0"); 41 | userService.save(userEntity); 42 | 43 | UserBakEntity userBakEntity = new UserBakEntity(); 44 | userBakEntity.setId(UuidUtil.generateUUID()); 45 | userBakEntity.setUserName("test0"); 46 | userBakEntity.setLoginName("test0"); 47 | userBakEntity.setPasswd("test0"); 48 | userBakService.save(userBakEntity); 49 | int i =1/0; 50 | 51 | return "OK"; 52 | 53 | } 54 | 55 | @GetMapping("/testTrans1") 56 | @Transactional 57 | public String testTrans1() { 58 | 59 | UserEntity userEntity = new UserEntity(); 60 | userEntity.setId(UuidUtil.generateUUID()); 61 | userEntity.setUserName("test1"); 62 | userEntity.setLoginName("test1"); 63 | userEntity.setPasswd("test1"); 64 | userService.save(userEntity); 65 | // int i =1/0; 66 | return "ok"; 67 | 68 | } 69 | 70 | @GetMapping("/testTrans2") 71 | @Transactional 72 | public String testTrans2() { 73 | UserBakEntity userBakEntity = new UserBakEntity(); 74 | userBakEntity.setId(UuidUtil.generateUUID()); 75 | userBakEntity.setUserName("test2"); 76 | userBakEntity.setLoginName("test2"); 77 | userBakEntity.setPasswd("test2"); 78 | userBakService.save(userBakEntity); 79 | // int i =1/0; 80 | return "ok"; 81 | 82 | } 83 | @GetMapping("/getData1") 84 | public List getData1() { 85 | return userService.selectByAll(); 86 | 87 | } 88 | @GetMapping("/getData2") 89 | public List getData2() { 90 | return userBakService.selectByAll(); 91 | 92 | } 93 | } -------------------------------------------------------------------------------- /src/main/java/com/lishuangqi/datasources/DataSourceNames.java: -------------------------------------------------------------------------------- 1 | package com.lishuangqi.datasources; 2 | 3 | /** 4 | * 增加多数据源,在此配置 5 | * 6 | * @author chenshun 7 | * @email sunlightcs@gmail.com 8 | * @date 2017/8/18 23:46 9 | */ 10 | public interface DataSourceNames { 11 | String DB1 = "db1"; 12 | String DB2 = "db2"; 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/lishuangqi/datasources/DynamicDataSource.java: -------------------------------------------------------------------------------- 1 | package com.lishuangqi.datasources; 2 | 3 | import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; 4 | 5 | import javax.sql.DataSource; 6 | import java.util.Map; 7 | 8 | /** 9 | * 动态数据源 10 | * @author chenshun 11 | * @email sunlightcs@gmail.com 12 | * @date 2017/8/19 1:03 13 | */ 14 | public class DynamicDataSource extends AbstractRoutingDataSource { 15 | private static final ThreadLocal contextHolder = new ThreadLocal<>(); 16 | 17 | public DynamicDataSource(DataSource defaultTargetDataSource, Map targetDataSources) { 18 | super.setDefaultTargetDataSource(defaultTargetDataSource); 19 | super.setTargetDataSources(targetDataSources); 20 | super.afterPropertiesSet(); 21 | } 22 | 23 | @Override 24 | protected Object determineCurrentLookupKey() { 25 | return getDataSource(); 26 | } 27 | 28 | public static void setDataSource(String dataSource) { 29 | contextHolder.set(dataSource); 30 | } 31 | 32 | public static String getDataSource() { 33 | return contextHolder.get(); 34 | } 35 | 36 | public static void clearDataSource() { 37 | contextHolder.remove(); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/lishuangqi/datasources/DynamicDataSourceConfig.java: -------------------------------------------------------------------------------- 1 | package com.lishuangqi.datasources; 2 | 3 | import com.alibaba.druid.filter.stat.StatFilter; 4 | import com.alibaba.druid.support.http.StatViewServlet; 5 | import com.alibaba.druid.support.http.WebStatFilter; 6 | import com.alibaba.druid.wall.WallConfig; 7 | import com.alibaba.druid.wall.WallFilter; 8 | import com.atomikos.icatch.jta.UserTransactionImp; 9 | import com.atomikos.icatch.jta.UserTransactionManager; 10 | import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean; 11 | import org.apache.ibatis.session.SqlSessionFactory; 12 | import org.mybatis.spring.SqlSessionTemplate; 13 | import org.springframework.beans.factory.annotation.Qualifier; 14 | import org.springframework.beans.factory.annotation.Value; 15 | import org.springframework.boot.jta.atomikos.AtomikosDataSourceBean; 16 | import org.springframework.boot.web.servlet.FilterRegistrationBean; 17 | import org.springframework.boot.web.servlet.ServletRegistrationBean; 18 | import org.springframework.context.annotation.Bean; 19 | import org.springframework.context.annotation.Configuration; 20 | import org.springframework.context.annotation.Primary; 21 | import org.springframework.core.env.Environment; 22 | import org.springframework.transaction.jta.JtaTransactionManager; 23 | 24 | import javax.sql.DataSource; 25 | import javax.transaction.SystemException; 26 | import java.util.HashMap; 27 | import java.util.Map; 28 | import java.util.Properties; 29 | 30 | /** 31 | * 配置多数据源 32 | * 33 | * @author chenshun 34 | * @email sunlightcs@gmail.com 35 | * @date 2017/8/19 0:41 36 | */ 37 | @Configuration 38 | public class DynamicDataSourceConfig { 39 | public static final String basePackage ="spring.datasource.druid."; 40 | @Value("${spring.datasource.type:com.alibaba.druid.pool.xa.DruidXADataSource}") 41 | String xaDataSourceClassName; 42 | 43 | @Primary 44 | @Bean(name = "db1DataSource") 45 | public DataSource db1DataSource(Environment env) { 46 | String sourceName = DataSourceNames.DB1; 47 | Properties prop = build(env, basePackage+sourceName+"."); 48 | // DruidXADataSource druidXADataSource = new DruidXADataSource(); 49 | // druidXADataSource.setUrl(prop.getProperty("url")); 50 | // druidXADataSource.setUsername(prop.getProperty("username")); 51 | // druidXADataSource.setPassword(prop.getProperty("password")); 52 | 53 | // MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource(); 54 | // mysqlXaDataSource.setUrl(prop.getProperty("url")); 55 | // mysqlXaDataSource.setUser(prop.getProperty("username")); 56 | // mysqlXaDataSource.setPassword(prop.getProperty("password")); 57 | 58 | AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean(); 59 | // xaDataSource.setXaDataSource(druidXADataSource); 60 | xaDataSource.setXaDataSourceClassName(xaDataSourceClassName); 61 | xaDataSource.setUniqueResourceName(sourceName); 62 | xaDataSource.setPoolSize(5); 63 | xaDataSource.setXaProperties(prop); 64 | return xaDataSource; 65 | } 66 | 67 | @Bean(name = "db2DataSource") 68 | public DataSource db2DataSource(Environment env) { 69 | String sourceName = DataSourceNames.DB2; 70 | Properties prop = build(env, basePackage+sourceName+"."); 71 | 72 | AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean(); 73 | xaDataSource.setXaDataSourceClassName(xaDataSourceClassName); 74 | xaDataSource.setUniqueResourceName(sourceName); 75 | xaDataSource.setPoolSize(5); 76 | xaDataSource.setXaProperties(prop); 77 | return xaDataSource; 78 | 79 | } 80 | 81 | // 配置数据源 82 | @Bean(name = "dynamicDataSource") 83 | public DynamicDataSource dataSource(@Qualifier("db1DataSource") DataSource db1DataSource, 84 | @Qualifier("db2DataSource") DataSource db2DataSource) { 85 | Map targetDataSources = new HashMap<>(); 86 | targetDataSources.put(DataSourceNames.DB1, db1DataSource); 87 | targetDataSources.put(DataSourceNames.DB2, db2DataSource); 88 | return new DynamicDataSource(db1DataSource, targetDataSources); 89 | } 90 | @Primary 91 | @Bean(name = "sqlSessionFactory") 92 | public SqlSessionFactory sqlSessionFactory(@Qualifier("dynamicDataSource") DataSource dataSource) 93 | throws Exception { 94 | MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean(); 95 | bean.setDataSource(dataSource); 96 | bean.setTransactionFactory(new MultiDataSourceTransactionFactory()); 97 | // bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/**/*Dao.xml"));// 扫描指定目录的xml 98 | return bean.getObject(); 99 | } 100 | @Bean(name="sqlSessionTemplate") 101 | @Primary 102 | public SqlSessionTemplate sqlSessionTemplate(@Qualifier("sqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception { 103 | return new SqlSessionTemplate(sqlSessionFactory); 104 | } 105 | 106 | /** 107 | * 分布式事务使用JTA管理,不管有多少个数据源只要配置一个 JtaTransactionManager 108 | * @return 109 | */ 110 | /*atomikos事务管理器*/ 111 | public UserTransactionManager userTransactionManager() { 112 | UserTransactionManager userTransactionManager = new UserTransactionManager(); 113 | userTransactionManager.setForceShutdown(true); 114 | return userTransactionManager; 115 | } 116 | 117 | public UserTransactionImp userTransactionImp() throws SystemException { 118 | UserTransactionImp userTransactionImp = new UserTransactionImp(); 119 | userTransactionImp.setTransactionTimeout(5000); 120 | return userTransactionImp; 121 | } 122 | 123 | @Bean 124 | public JtaTransactionManager jtaTransactionManager() throws SystemException { 125 | JtaTransactionManager jtaTransactionManager = new JtaTransactionManager(); 126 | jtaTransactionManager.setTransactionManager(userTransactionManager()); 127 | jtaTransactionManager.setUserTransaction(userTransactionImp()); 128 | jtaTransactionManager.setAllowCustomIsolationLevels(true); 129 | return jtaTransactionManager; 130 | } 131 | 132 | 133 | private Properties build(Environment env, String prefix) { 134 | 135 | Properties prop = new Properties(); 136 | prop.put("url", env.getProperty(prefix + "url")); 137 | prop.put("username", env.getProperty(prefix + "username")); 138 | prop.put("password", env.getProperty(prefix + "password")); 139 | prop.put("driverClassName", env.getProperty(prefix + "driverClassName", "")); 140 | prop.put("initialSize", env.getProperty(prefix + "initialSize", Integer.class)); 141 | prop.put("maxActive", env.getProperty(prefix + "maxActive", Integer.class)); 142 | prop.put("minIdle", env.getProperty(prefix + "minIdle", Integer.class)); 143 | prop.put("maxWait", env.getProperty(prefix + "maxWait", Integer.class)); 144 | prop.put("poolPreparedStatements", env.getProperty(prefix + "poolPreparedStatements", Boolean.class)); 145 | 146 | prop.put("maxPoolPreparedStatementPerConnectionSize", 147 | env.getProperty(prefix + "maxPoolPreparedStatementPerConnectionSize", Integer.class)); 148 | 149 | prop.put("maxPoolPreparedStatementPerConnectionSize", 150 | env.getProperty(prefix + "maxPoolPreparedStatementPerConnectionSize", Integer.class)); 151 | prop.put("validationQuery", env.getProperty(prefix + "validationQuery")); 152 | prop.put("validationQueryTimeout", env.getProperty(prefix + "validationQueryTimeout", Integer.class)); 153 | prop.put("testOnBorrow", env.getProperty(prefix + "testOnBorrow", Boolean.class)); 154 | prop.put("testOnReturn", env.getProperty(prefix + "testOnReturn", Boolean.class)); 155 | prop.put("testWhileIdle", env.getProperty(prefix + "testWhileIdle", Boolean.class)); 156 | prop.put("timeBetweenEvictionRunsMillis", 157 | env.getProperty(prefix + "timeBetweenEvictionRunsMillis", Integer.class)); 158 | prop.put("minEvictableIdleTimeMillis", env.getProperty(prefix + "minEvictableIdleTimeMillis", Integer.class)); 159 | prop.put("filters", env.getProperty(prefix + "filters")); 160 | 161 | return prop; 162 | } 163 | 164 | @Bean 165 | public ServletRegistrationBean druidServlet() { 166 | ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*"); 167 | 168 | //控制台管理用户,加入下面2行 进入druid后台就需要登录 169 | //servletRegistrationBean.addInitParameter("loginUsername", "admin"); 170 | //servletRegistrationBean.addInitParameter("loginPassword", "admin"); 171 | return servletRegistrationBean; 172 | } 173 | 174 | @Bean 175 | public FilterRegistrationBean filterRegistrationBean() { 176 | FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); 177 | filterRegistrationBean.setFilter(new WebStatFilter()); 178 | filterRegistrationBean.addUrlPatterns("/*"); 179 | filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"); 180 | filterRegistrationBean.addInitParameter("profileEnable", "true"); 181 | return filterRegistrationBean; 182 | } 183 | 184 | @Bean 185 | public StatFilter statFilter(){ 186 | StatFilter statFilter = new StatFilter(); 187 | statFilter.setLogSlowSql(true); //slowSqlMillis用来配置SQL慢的标准,执行时间超过slowSqlMillis的就是慢。 188 | statFilter.setMergeSql(true); //SQL合并配置 189 | statFilter.setSlowSqlMillis(1000);//slowSqlMillis的缺省值为3000,也就是3秒。 190 | return statFilter; 191 | } 192 | 193 | @Bean 194 | public WallFilter wallFilter(){ 195 | WallFilter wallFilter = new WallFilter(); 196 | //允许执行多条SQL 197 | WallConfig config = new WallConfig(); 198 | config.setMultiStatementAllow(true); 199 | wallFilter.setConfig(config); 200 | return wallFilter; 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /src/main/java/com/lishuangqi/datasources/MultiDataSourceTransaction.java: -------------------------------------------------------------------------------- 1 | package com.lishuangqi.datasources; 2 | 3 | import com.alibaba.druid.support.logging.Log; 4 | import com.alibaba.druid.support.logging.LogFactory; 5 | import org.apache.ibatis.transaction.Transaction; 6 | import org.springframework.jdbc.CannotGetJdbcConnectionException; 7 | import org.springframework.jdbc.datasource.DataSourceUtils; 8 | 9 | import javax.sql.DataSource; 10 | import java.sql.Connection; 11 | import java.sql.SQLException; 12 | import java.util.concurrent.ConcurrentHashMap; 13 | import java.util.concurrent.ConcurrentMap; 14 | 15 | import static org.apache.commons.lang3.Validate.notNull; 16 | 17 | /** 18 | *

多数据源切换,支持事务

19 | * 20 | * @author lishuangqi 21 | * @date 2019/5/16 15:09 22 | * @since 23 | */ 24 | public class MultiDataSourceTransaction implements Transaction{ 25 | private static final Log LOGGER = LogFactory.getLog(MultiDataSourceTransaction.class); 26 | 27 | private final DataSource dataSource; 28 | 29 | private Connection mainConnection; 30 | 31 | private String mainDatabaseIdentification; 32 | 33 | private ConcurrentMap otherConnectionMap; 34 | 35 | 36 | private boolean isConnectionTransactional; 37 | 38 | private boolean autoCommit; 39 | 40 | 41 | public MultiDataSourceTransaction(DataSource dataSource) { 42 | notNull(dataSource, "No DataSource specified"); 43 | this.dataSource = dataSource; 44 | otherConnectionMap = new ConcurrentHashMap<>(); 45 | mainDatabaseIdentification=DynamicDataSource.getDataSource(); 46 | } 47 | 48 | 49 | /** 50 | * {@inheritDoc} 51 | */ 52 | @Override 53 | public Connection getConnection() throws SQLException { 54 | String databaseIdentification = DynamicDataSource.getDataSource(); 55 | if (databaseIdentification.equals(mainDatabaseIdentification)) { 56 | if (mainConnection != null) return mainConnection; 57 | else { 58 | openMainConnection(); 59 | mainDatabaseIdentification =databaseIdentification; 60 | return mainConnection; 61 | } 62 | } else { 63 | if (!otherConnectionMap.containsKey(databaseIdentification)) { 64 | try { 65 | Connection conn = dataSource.getConnection(); 66 | otherConnectionMap.put(databaseIdentification, conn); 67 | } catch (SQLException ex) { 68 | throw new CannotGetJdbcConnectionException("Could not get JDBC Connection", ex); 69 | } 70 | } 71 | return otherConnectionMap.get(databaseIdentification); 72 | } 73 | 74 | } 75 | 76 | 77 | private void openMainConnection() throws SQLException { 78 | this.mainConnection = DataSourceUtils.getConnection(this.dataSource); 79 | this.autoCommit = this.mainConnection.getAutoCommit(); 80 | this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.mainConnection, this.dataSource); 81 | 82 | if (LOGGER.isDebugEnabled()) { 83 | LOGGER.debug( 84 | "JDBC Connection [" 85 | + this.mainConnection 86 | + "] will" 87 | + (this.isConnectionTransactional ? " " : " not ") 88 | + "be managed by Spring"); 89 | } 90 | } 91 | 92 | /** 93 | * {@inheritDoc} 94 | */ 95 | @Override 96 | public void commit() throws SQLException { 97 | if (this.mainConnection != null && !this.isConnectionTransactional && !this.autoCommit) { 98 | if (LOGGER.isDebugEnabled()) { 99 | LOGGER.debug("Committing JDBC Connection [" + this.mainConnection + "]"); 100 | } 101 | this.mainConnection.commit(); 102 | for (Connection connection : otherConnectionMap.values()) { 103 | connection.commit(); 104 | } 105 | } 106 | } 107 | 108 | /** 109 | * {@inheritDoc} 110 | */ 111 | @Override 112 | public void rollback() throws SQLException { 113 | if (this.mainConnection != null && !this.isConnectionTransactional && !this.autoCommit) { 114 | if (LOGGER.isDebugEnabled()) { 115 | LOGGER.debug("Rolling back JDBC Connection [" + this.mainConnection + "]"); 116 | } 117 | this.mainConnection.rollback(); 118 | for (Connection connection : otherConnectionMap.values()) { 119 | connection.rollback(); 120 | } 121 | } 122 | } 123 | 124 | /** 125 | * {@inheritDoc} 126 | */ 127 | @Override 128 | public void close() throws SQLException { 129 | DataSourceUtils.releaseConnection(this.mainConnection, this.dataSource); 130 | for (Connection connection : otherConnectionMap.values()) { 131 | DataSourceUtils.releaseConnection(connection, this.dataSource); 132 | } 133 | } 134 | 135 | @Override 136 | public Integer getTimeout() throws SQLException { 137 | return null; 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/main/java/com/lishuangqi/datasources/MultiDataSourceTransactionFactory.java: -------------------------------------------------------------------------------- 1 | package com.lishuangqi.datasources; 2 | 3 | 4 | 5 | import org.apache.ibatis.session.TransactionIsolationLevel; 6 | import org.apache.ibatis.transaction.Transaction; 7 | import org.mybatis.spring.transaction.SpringManagedTransactionFactory; 8 | 9 | import javax.sql.DataSource; 10 | 11 | /** 12 | *

支持Service内多数据源切换的Factory

13 | * 14 | * @author lishuangqi 15 | * @date 2019/5/16 15:09 16 | * @since 17 | */ 18 | public class MultiDataSourceTransactionFactory extends SpringManagedTransactionFactory { 19 | @Override 20 | public Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit) { 21 | return new MultiDataSourceTransaction(dataSource); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/lishuangqi/datasources/aspect/DataSourceAspect.java: -------------------------------------------------------------------------------- 1 | package com.lishuangqi.datasources.aspect; 2 | 3 | import com.lishuangqi.annotation.DataSource; 4 | import com.lishuangqi.datasources.DataSourceNames; 5 | import com.lishuangqi.datasources.DynamicDataSource; 6 | import org.aspectj.lang.JoinPoint; 7 | import org.aspectj.lang.ProceedingJoinPoint; 8 | import org.aspectj.lang.annotation.After; 9 | import org.aspectj.lang.annotation.Around; 10 | import org.aspectj.lang.annotation.Aspect; 11 | import org.aspectj.lang.annotation.Pointcut; 12 | import org.aspectj.lang.reflect.MethodSignature; 13 | import org.slf4j.Logger; 14 | import org.slf4j.LoggerFactory; 15 | import org.springframework.context.annotation.Configuration; 16 | import org.springframework.core.annotation.Order; 17 | 18 | import java.lang.reflect.Method; 19 | 20 | /** 21 | * 多数据源,切面处理类 22 | * 23 | * @author chenshun 24 | * @email sunlightcs@gmail.com 25 | * @date 2017/9/16 22:20 26 | */ 27 | @Aspect 28 | @Configuration 29 | @Order(0) 30 | public class DataSourceAspect { 31 | protected Logger logger = LoggerFactory.getLogger(getClass()); 32 | 33 | // com.baomidou.mybatisplus.extension.service.impl 34 | @Pointcut("execution(* com.lishuangqi.*.service.impl.*.*(..)) && @target(com.lishuangqi.annotation.DataSource)") 35 | public void dataSourcePointCut() { 36 | 37 | } 38 | 39 | // @Before("dataSourcePointCut()") 40 | // public void intercept(JoinPoint point) throws Exception { 41 | // Class target = point.getTarget().getClass(); 42 | // MethodSignature signature = (MethodSignature) point.getSignature(); 43 | //// for (Class clazz : target.getInterfaces()) { 44 | //// resolveDataSource(clazz, signature.getMethod()); 45 | //// } 46 | //// resolveDataSource(target, signature.getMethod()); 47 | // Method method = signature.getMethod(); 48 | // resolveDataSource(target, method); 49 | // 50 | // } 51 | 52 | @Around("dataSourcePointCut()") 53 | public Object around(ProceedingJoinPoint point) throws Throwable { 54 | DataSource ds = null; 55 | Class target = point.getTarget().getClass(); 56 | MethodSignature signature = (MethodSignature) point.getSignature(); 57 | Method method = signature.getMethod(); 58 | ds = resolveDataSource(target, method); 59 | 60 | if (ds == null) { 61 | DynamicDataSource.setDataSource(DataSourceNames.DB1); 62 | logger.info("set default datasource is " + DataSourceNames.DB1); 63 | } else { 64 | DynamicDataSource.setDataSource(ds.name()); 65 | logger.info("set datasource is " + ds.name()); 66 | } 67 | return point.proceed(); 68 | } 69 | 70 | @After("dataSourcePointCut()") 71 | public void restoreDataSource(JoinPoint point) { 72 | DynamicDataSource.clearDataSource(); 73 | } 74 | 75 | /* 76 | * 获取最终的dataSource 77 | * 78 | * @param clazz 79 | * @param method 80 | */ 81 | private DataSource resolveDataSource(Class clazz, Method method) { 82 | try { 83 | DataSource ds = null; 84 | Class[] types = method.getParameterTypes(); 85 | // 默认使用类型注解 86 | if (clazz.isAnnotationPresent(DataSource.class)) { 87 | ds = clazz.getAnnotation(DataSource.class); 88 | // DynamicDataSource.setDataSource(ds.name()); 89 | // logger.info("set datasource is " + ds.name()); 90 | // logger.info(DynamicDataSource.getDataSource()); 91 | } 92 | // 方法注解可以覆盖类型注解 93 | Method m = clazz.getMethod(method.getName(), types); 94 | if (m != null && m.isAnnotationPresent(DataSource.class)) { 95 | ds = m.getAnnotation(DataSource.class); 96 | // DynamicDataSource.setDataSource(ds.name()); 97 | // logger.info("set datasource is " + ds.name()); 98 | // logger.info(DynamicDataSource.getDataSource()); 99 | } 100 | return ds; 101 | } catch (Exception e) { 102 | System.out.println(clazz + ":" + e.getMessage()); 103 | } 104 | return null; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/com/lishuangqi/db1/dao/UserDao.java: -------------------------------------------------------------------------------- 1 | package com.lishuangqi.db1.dao; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.lishuangqi.db1.entity.UserEntity; 5 | import org.apache.ibatis.annotations.Select; 6 | 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | /** 11 | * 用户表 12 | * 13 | * @author flyCloud 14 | * @email 15 | * @date 2018-08-31 15:01:21 16 | */ 17 | public interface UserDao extends BaseMapper { 18 | 19 | /** 20 | * 查询出所有用户的信息,用于IM服务器接口提供 21 | * @return 22 | */ 23 | @Select("SELECT * FROM t_sys_user WHERE u.DELETED=0 AND u.state=0") 24 | List> findAllUser(); 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/lishuangqi/db1/entity/UserEntity.java: -------------------------------------------------------------------------------- 1 | package com.lishuangqi.db1.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableId; 4 | import com.baomidou.mybatisplus.annotation.TableName; 5 | import lombok.Data; 6 | 7 | import java.io.Serializable; 8 | 9 | /** 10 | * 用户表 11 | * 12 | * @author flyCloud 13 | * @email 14 | * @date 2018-08-31 15:01:21 15 | */ 16 | @TableName("user") 17 | @Data 18 | public class UserEntity implements Serializable { 19 | private static final long serialVersionUID = 1L; 20 | 21 | /** 22 | * ID 23 | */ 24 | @TableId 25 | private String id; 26 | /** 27 | * ???ID 28 | */ 29 | private String deptId; 30 | /** 31 | * 登录帐号 32 | */ 33 | private String loginName; 34 | /** 35 | * 登录密码 36 | */ 37 | private String passwd; 38 | /** 39 | * 用户名称 40 | */ 41 | private String userName; 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/lishuangqi/db1/package-info.java: -------------------------------------------------------------------------------- 1 | package com.lishuangqi.db1; -------------------------------------------------------------------------------- /src/main/java/com/lishuangqi/db1/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.lishuangqi.db1.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.lishuangqi.db1.entity.UserEntity; 5 | 6 | import java.io.Serializable; 7 | import java.util.List; 8 | 9 | /** 10 | * 用户表 11 | * 12 | * @author flyCloud 13 | * @email 14 | * @date 2018-08-31 15:01:21 15 | */ 16 | public interface UserService extends IService { 17 | 18 | /** 19 | * @Description 说明: 20 | * @param loginName 登录账号 21 | * @return 22 | */ 23 | UserEntity login(String loginName); 24 | 25 | /** 26 | * 更新密码 27 | * @param userId 28 | * @param newPassWord 29 | */ 30 | boolean updatePassWord(String userId, String newPassWord); 31 | 32 | 33 | /** 34 | * 更新数据 35 | * @param entity 36 | * @return 37 | */ 38 | boolean modifyUserInfo(UserEntity entity); 39 | 40 | 41 | UserEntity selectById(Serializable id); 42 | 43 | List selectByAll(); 44 | } 45 | 46 | -------------------------------------------------------------------------------- /src/main/java/com/lishuangqi/db1/service/impl/UserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.lishuangqi.db1.service.impl; 2 | 3 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 4 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 5 | import com.lishuangqi.annotation.DataSource; 6 | import com.lishuangqi.db1.dao.UserDao; 7 | import com.lishuangqi.db1.entity.UserEntity; 8 | import com.lishuangqi.db1.service.UserService; 9 | import org.springframework.stereotype.Service; 10 | import org.springframework.transaction.annotation.Transactional; 11 | 12 | import java.io.Serializable; 13 | import java.util.List; 14 | 15 | 16 | @Service("userService") 17 | @DataSource(name="db1") 18 | public class UserServiceImpl extends ServiceImpl implements UserService { 19 | 20 | @Override 21 | public UserEntity login(String loginName) { 22 | UserEntity i = baseMapper.selectOne(new QueryWrapper().eq("login_name", loginName)); 23 | return i; 24 | } 25 | 26 | @Override 27 | public boolean updatePassWord(String userId, String newPassWord) { 28 | UserEntity entity = new UserEntity(); 29 | entity.setId(userId); 30 | entity.setPasswd(newPassWord); 31 | return super.updateById(entity); 32 | } 33 | 34 | @Override 35 | @Transactional 36 | public boolean save(UserEntity entity) { 37 | // int i = 1/0; 38 | return super.save(entity); 39 | } 40 | 41 | @Override 42 | public boolean modifyUserInfo(UserEntity entity) { 43 | if(entity == null) { 44 | return false; 45 | } 46 | return this.updateById(entity); 47 | } 48 | 49 | @Override 50 | public UserEntity selectById(Serializable id) { 51 | return baseMapper.selectById(id); 52 | } 53 | 54 | @Override 55 | public List selectByAll(){ 56 | return baseMapper.selectList(null); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/lishuangqi/db2/dao/UserBakDao.java: -------------------------------------------------------------------------------- 1 | package com.lishuangqi.db2.dao; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.lishuangqi.db2.entity.UserBakEntity; 5 | import org.apache.ibatis.annotations.Select; 6 | 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | /** 11 | * 用户表 12 | * 13 | * @author flyCloud 14 | * @email 15 | * @date 2018-08-31 15:01:21 16 | */ 17 | public interface UserBakDao extends BaseMapper { 18 | 19 | /** 20 | * 查询出所有用户的信息,用于IM服务器接口提供 21 | * @return 22 | */ 23 | @Select("SELECT * FROM user ") 24 | List> findAllUser(); 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/lishuangqi/db2/entity/UserBakEntity.java: -------------------------------------------------------------------------------- 1 | package com.lishuangqi.db2.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableId; 4 | import com.baomidou.mybatisplus.annotation.TableName; 5 | import lombok.Data; 6 | 7 | import java.io.Serializable; 8 | 9 | /** 10 | * 用户表 11 | * 12 | * @author flyCloud 13 | * @email 14 | * @date 2018-08-31 15:01:21 15 | */ 16 | @TableName("user") 17 | @Data 18 | public class UserBakEntity implements Serializable { 19 | private static final long serialVersionUID = 1L; 20 | 21 | /** 22 | * ID 23 | */ 24 | @TableId 25 | private String id; 26 | /** 27 | * ???ID 28 | */ 29 | private String deptId; 30 | /** 31 | * 登录帐号 32 | */ 33 | private String loginName; 34 | /** 35 | * 登录密码 36 | */ 37 | private String passwd; 38 | /** 39 | * 用户名称 40 | */ 41 | private String userName; 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/lishuangqi/db2/service/UserBakService.java: -------------------------------------------------------------------------------- 1 | package com.lishuangqi.db2.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.lishuangqi.db2.entity.UserBakEntity; 5 | 6 | import java.io.Serializable; 7 | import java.util.List; 8 | 9 | /** 10 | * 用户表 11 | * 12 | * @author flyCloud 13 | * @email 14 | * @date 2018-08-31 15:01:21 15 | */ 16 | public interface UserBakService extends IService { 17 | 18 | /** 19 | * @Description 说明: 20 | * @param loginName 登录账号 21 | * @return 22 | */ 23 | UserBakEntity login(String loginName); 24 | 25 | /** 26 | * 更新密码 27 | * @param userId 28 | * @param newPassWord 29 | */ 30 | boolean updatePassWord(String userId, String newPassWord); 31 | 32 | 33 | /** 34 | * 更新数据 35 | * @param entity 36 | * @return 37 | */ 38 | boolean modifyUserInfo(UserBakEntity entity); 39 | 40 | 41 | UserBakEntity selectById(Serializable id); 42 | 43 | List selectByAll(); 44 | } 45 | 46 | -------------------------------------------------------------------------------- /src/main/java/com/lishuangqi/db2/service/impl/UserBakServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.lishuangqi.db2.service.impl; 2 | 3 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 4 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 5 | import com.lishuangqi.annotation.DataSource; 6 | import com.lishuangqi.db2.dao.UserBakDao; 7 | import com.lishuangqi.db2.entity.UserBakEntity; 8 | import com.lishuangqi.db2.service.UserBakService; 9 | import org.springframework.stereotype.Service; 10 | import org.springframework.transaction.annotation.Transactional; 11 | 12 | import java.io.Serializable; 13 | import java.util.List; 14 | 15 | 16 | @Service("userBakService") 17 | @DataSource(name="db2") 18 | public class UserBakServiceImpl extends ServiceImpl implements UserBakService { 19 | 20 | @Override 21 | public UserBakEntity login(String loginName) { 22 | UserBakEntity i = baseMapper.selectOne(new QueryWrapper().eq("login_name", loginName)); 23 | return i; 24 | } 25 | 26 | @Override 27 | public boolean updatePassWord(String userId, String newPassWord) { 28 | UserBakEntity entity = new UserBakEntity(); 29 | entity.setId(userId); 30 | entity.setPasswd(newPassWord); 31 | return super.updateById(entity); 32 | } 33 | 34 | @Override 35 | @Transactional 36 | public boolean save(UserBakEntity entity) { 37 | // int i = 1/0; 38 | return super.save(entity); 39 | } 40 | 41 | @Override 42 | public boolean modifyUserInfo(UserBakEntity entity) { 43 | if(entity == null) { 44 | return false; 45 | } 46 | return this.updateById(entity); 47 | } 48 | 49 | @Override 50 | public UserBakEntity selectById(Serializable id) { 51 | return baseMapper.selectById(id); 52 | } 53 | 54 | @Override 55 | public List selectByAll(){ 56 | return baseMapper.selectList(null); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/lishuangqi/utils/PageQuery.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018 人人开源 http://www.renren.io 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package com.lishuangqi.utils; 18 | 19 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 20 | import org.apache.commons.lang3.StringUtils; 21 | 22 | import java.util.LinkedHashMap; 23 | import java.util.Map; 24 | 25 | /** 26 | * 查询参数 27 | * 28 | * @author Mark sunlightcs@gmail.com 29 | * @since 2.0.0 2017-03-14 30 | */ 31 | public class PageQuery extends LinkedHashMap { 32 | private static final long serialVersionUID = 1L; 33 | /** 34 | * mybatis-plus分页参数 35 | */ 36 | private Page page; 37 | /** 38 | * 当前页码 39 | */ 40 | private int currPage = 1; 41 | /** 42 | * 每页条数 43 | */ 44 | private int limit = 10; 45 | 46 | public PageQuery(Map params){ 47 | this.putAll(params); 48 | 49 | //分页参数 50 | if(params.get("page") != null){ 51 | currPage = Integer.parseInt((String)params.get("page")); 52 | } 53 | if(params.get("limit") != null){ 54 | limit = Integer.parseInt((String)params.get("limit")); 55 | } 56 | 57 | this.put("offset", (currPage - 1) * limit); 58 | this.put("page", currPage); 59 | this.put("limit", limit); 60 | 61 | //防止SQL注入(因为sidx、order是通过拼接SQL实现排序的,会有SQL注入风险) 62 | String sidx = SQLFilter.sqlInject((String)params.get("sidx")); 63 | String order = SQLFilter.sqlInject((String)params.get("order")); 64 | this.put("sidx", sidx); 65 | this.put("order", order); 66 | 67 | //mybatis-plus分页 68 | this.page = new Page<>(currPage, limit); 69 | 70 | //排序 71 | if(StringUtils.isNotBlank(sidx) && StringUtils.isNotBlank(order)){ 72 | if("ASC".equalsIgnoreCase(order)){ 73 | this.page.setAsc(sidx); 74 | }else { 75 | this.page.setDesc(sidx); 76 | } 77 | } 78 | 79 | } 80 | 81 | public Page getPage() { 82 | return page; 83 | } 84 | 85 | public int getCurrPage() { 86 | return currPage; 87 | } 88 | 89 | public int getLimit() { 90 | return limit; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/com/lishuangqi/utils/PageUtils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018 人人开源 http://www.renren.io 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package com.lishuangqi.utils; 18 | 19 | 20 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 21 | 22 | import java.io.Serializable; 23 | import java.util.List; 24 | 25 | /** 26 | * 分页工具类 27 | * 28 | * @author chenshun 29 | * @email sunlightcs@gmail.com 30 | * @date 2016年11月4日 下午12:59:00 31 | */ 32 | public class PageUtils implements Serializable { 33 | private static final long serialVersionUID = 1L; 34 | //总记录数 35 | private long totalCount; 36 | //每页记录数 37 | private long pageSize; 38 | //总页数 39 | private long totalPage; 40 | //当前页数 41 | private long currPage; 42 | //列表数据 43 | private List list; 44 | 45 | /** 46 | * 分页 47 | * @param list 列表数据 48 | * @param totalCount 总记录数 49 | * @param pageSize 每页记录数 50 | * @param currPage 当前页数 51 | */ 52 | public PageUtils(List list, long totalCount, long pageSize, long currPage) { 53 | this.list = list; 54 | this.totalCount = totalCount; 55 | this.pageSize = pageSize; 56 | this.currPage = currPage; 57 | this.totalPage = (long)Math.ceil((double)totalCount/pageSize); 58 | } 59 | 60 | /** 61 | * 分页 62 | */ 63 | public PageUtils(Page page) { 64 | this.list = page.getRecords(); 65 | this.totalCount = page.getTotal(); 66 | this.pageSize = page.getSize(); 67 | this.currPage = page.getCurrent(); 68 | this.totalPage = page.getPages(); 69 | } 70 | 71 | public long getTotalCount() { 72 | return totalCount; 73 | } 74 | 75 | public void setTotalCount(long totalCount) { 76 | this.totalCount = totalCount; 77 | } 78 | 79 | public long getPageSize() { 80 | return pageSize; 81 | } 82 | 83 | public void setPageSize(long pageSize) { 84 | this.pageSize = pageSize; 85 | } 86 | 87 | public long getTotalPage() { 88 | return totalPage; 89 | } 90 | 91 | public void setTotalPage(long totalPage) { 92 | this.totalPage = totalPage; 93 | } 94 | 95 | public long getCurrPage() { 96 | return currPage; 97 | } 98 | 99 | public void setCurrPage(long currPage) { 100 | this.currPage = currPage; 101 | } 102 | 103 | public List getList() { 104 | return list; 105 | } 106 | 107 | public void setList(List list) { 108 | this.list = list; 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /src/main/java/com/lishuangqi/utils/R.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018 人人开源 http://www.renren.io 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package com.lishuangqi.utils; 18 | 19 | import java.util.HashMap; 20 | import java.util.Map; 21 | 22 | /** 23 | * 返回数据 24 | * 25 | * @author chenshun 26 | * @email sunlightcs@gmail.com 27 | * @date 2016年10月27日 下午9:59:27 28 | */ 29 | public class R extends HashMap { 30 | private static final long serialVersionUID = 1L; 31 | private static final String DATA = "data"; 32 | public R() { 33 | put("code", 0); 34 | put("msg", "success"); 35 | } 36 | 37 | public static R error() { 38 | return error(500, "未知异常,请联系管理员"); 39 | } 40 | 41 | public static R error(String msg) { 42 | return error(500, msg); 43 | } 44 | 45 | public static R error(int code, String msg) { 46 | R r = new R(); 47 | r.put("code", code); 48 | r.put("msg", msg); 49 | return r; 50 | } 51 | 52 | public static R ok(String msg) { 53 | R r = new R(); 54 | r.put("msg", msg); 55 | return r; 56 | } 57 | 58 | public static R ok(Map map) { 59 | R r = new R(); 60 | r.putAll(map); 61 | return r; 62 | } 63 | 64 | public static R ok() { 65 | return new R(); 66 | } 67 | 68 | public static R ok(Object result) { 69 | R r = new R(); 70 | r.put(DATA, result); 71 | return r; 72 | } 73 | 74 | @Override 75 | public R put(String key, Object value) { 76 | super.put(key, value); 77 | return this; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/lishuangqi/utils/RRException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018 人人开源 http://www.renren.io 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package com.lishuangqi.utils; 18 | 19 | /** 20 | * 自定义异常 21 | * 22 | * @author chenshun 23 | * @email sunlightcs@gmail.com 24 | * @date 2016年10月27日 下午10:11:27 25 | */ 26 | public class RRException extends RuntimeException { 27 | private static final long serialVersionUID = 1L; 28 | 29 | private String msg; 30 | private int code = 500; 31 | 32 | public RRException(String msg) { 33 | super(msg); 34 | this.msg = msg; 35 | } 36 | 37 | public RRException(String msg, Throwable e) { 38 | super(msg, e); 39 | this.msg = msg; 40 | } 41 | 42 | public RRException(String msg, int code) { 43 | super(msg); 44 | this.msg = msg; 45 | this.code = code; 46 | } 47 | 48 | public RRException(String msg, int code, Throwable e) { 49 | super(msg, e); 50 | this.msg = msg; 51 | this.code = code; 52 | } 53 | 54 | public String getMsg() { 55 | return msg; 56 | } 57 | 58 | public void setMsg(String msg) { 59 | this.msg = msg; 60 | } 61 | 62 | public int getCode() { 63 | return code; 64 | } 65 | 66 | public void setCode(int code) { 67 | this.code = code; 68 | } 69 | 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/lishuangqi/utils/SQLFilter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018 人人开源 http://www.renren.io 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package com.lishuangqi.utils; 18 | 19 | import org.apache.commons.lang3.StringUtils; 20 | 21 | /** 22 | * SQL过滤 23 | * @author chenshun 24 | * @email sunlightcs@gmail.com 25 | * @date 2017-04-01 16:16 26 | */ 27 | public class SQLFilter { 28 | 29 | /** 30 | * SQL注入过滤 31 | * @param str 待验证的字符串 32 | */ 33 | public static String sqlInject(String str){ 34 | if(StringUtils.isBlank(str)){ 35 | return null; 36 | } 37 | //去掉'|"|;|\字符 38 | str = StringUtils.replace(str, "'", ""); 39 | str = StringUtils.replace(str, "\"", ""); 40 | str = StringUtils.replace(str, ";", ""); 41 | str = StringUtils.replace(str, "\\", ""); 42 | 43 | //转换成小写 44 | str = str.toLowerCase(); 45 | 46 | //非法字符 47 | String[] keywords = {"master", "truncate", "insert", "select", "delete", "update", "declare", "alter", "drop"}; 48 | 49 | //判断是否包含非法字符 50 | for(String keyword : keywords){ 51 | if(str.indexOf(keyword) != -1){ 52 | throw new RRException("包含非法字符"); 53 | } 54 | } 55 | 56 | return str; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/lishuangqi/utils/UuidUtil.java: -------------------------------------------------------------------------------- 1 | package com.lishuangqi.utils; 2 | 3 | import java.util.UUID; 4 | 5 | /** 6 | * Created by michael on 2018/8/29. 7 | */ 8 | public class UuidUtil { 9 | public UuidUtil() { 10 | } 11 | 12 | public static String generateUUID() { 13 | String uuid = UUID.randomUUID().toString(); 14 | uuid = uuid.replace("-", ""); 15 | return uuid; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8101 3 | spring: 4 | datasource: 5 | type: com.alibaba.druid.pool.xa.DruidXADataSource 6 | druid: 7 | db1: #数据源1 8 | driverClassName: com.mysql.cj.jdbc.Driver 9 | url: jdbc:mysql://localhost:3306/adb1?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowMultiQueries=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai 10 | username: root 11 | password: nick1215 12 | initialSize: 10 13 | maxActive: 100 14 | minIdle: 10 15 | maxWait: 60000 16 | poolPreparedStatements: true 17 | maxPoolPreparedStatementPerConnectionSize: 20 18 | timeBetweenEvictionRunsMillis: 60000 19 | minEvictableIdleTimeMillis: 300000 20 | validationQuery: SELECT 1 FROM DUAL 21 | validationQueryTimeout: 10000 22 | testWhileIdle: true 23 | testOnBorrow: false 24 | testOnReturn: false 25 | statViewServlet: 26 | enabled: true 27 | urlPattern: /druid/* 28 | #login-username: admin 29 | #login-password: admin 30 | filters: stat,wall,log4j2 31 | db2: #数据源2 32 | driverClassName: com.mysql.cj.jdbc.Driver 33 | url: jdbc:mysql://localhost:3306/adb2?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowMultiQueries=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai 34 | username: root 35 | password: nick1215 36 | initialSize: 10 37 | maxActive: 100 38 | minIdle: 10 39 | maxWait: 60000 40 | poolPreparedStatements: true 41 | maxPoolPreparedStatementPerConnectionSize: 20 42 | timeBetweenEvictionRunsMillis: 60000 43 | minEvictableIdleTimeMillis: 300000 44 | validationQuery: SELECT 1 FROM DUAL 45 | validationQueryTimeout: 10000 46 | testWhileIdle: true 47 | testOnBorrow: false 48 | testOnReturn: false 49 | statViewServlet: 50 | enabled: true 51 | urlPattern: /druid/* 52 | #login-username: admin 53 | #login-password: admin 54 | filters: stat,wall,log4j2 55 | #jta相关参数配置 56 | jta: 57 | log-dir: classpath:tx-logs 58 | transaction-manager-id: txManager 59 | 60 | 61 | 62 | #mybatis 63 | mybatis-plus: 64 | mapper-locations: classpath*:mapper/**/*.xml 65 | #实体扫描,多个package用逗号或者分号分隔 66 | typeAliasesPackage: com.lishuangqi.*.entity 67 | typeEnumsPackage: com.baomidou.springboot.db.entity.enums 68 | global-config: 69 | #主键类型 0:"数据库ID自增", 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID"; 70 | id-type: UUID 71 | #字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断" 72 | field-strategy: not_empty 73 | #驼峰下划线转换 74 | column-underline: true 75 | #刷新mapper 调试神器 76 | # refresh-mapper: true 77 | #数据库大写下划线转换 78 | #capital-mode: true 79 | # Sequence序列接口实现类配置 80 | #key-generator: com.baomidou.mybatisplus.incrementer.OracleKeyGenerator 81 | #逻辑删除配置 82 | logic-delete-value: Y 83 | logic-not-delete-value: N 84 | # sql-injector: com.baomidou.mybatisplus.extension.injector.LogicSqlInjector 85 | configuration: 86 | map-underscore-to-camel-case: true 87 | cache-enabled: false 88 | call-setters-on-nulls: true 89 | 90 | logging: 91 | level: 92 | root: info 93 | com.atomikos: debug 94 | path: ./logs/ 95 | file: atomikos.log -------------------------------------------------------------------------------- /src/main/resources/bootstrap.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=test-server 2 | 3 | #spring.cloud.nacos.discovery.server-addr=nacos:8848 4 | #spring.cloud.nacos.discovery.namespace=f886be96-1142-4190-bab4-53fb7a7d39c2 5 | 6 | #默认情况下,会加载Data ID=${spring.application.name}.properties,Group=DEFAULT_GROUP的配置。 7 | #spring.cloud.nacos.config.server-addr=nacos:8848 8 | #spring.cloud.nacos.config.file-extension=yaml 9 | #spring.cloud.nacos.config.namespace=f886be96-1142-4190-bab4-53fb7a7d39c2 10 | 11 | #加载Group=MY_GROUP的配置。 12 | #spring.cloud.nacos.config.group=MY_GROUP 13 | #加载Data ID=${spring.application.name}-DEV.properties的配置。 14 | #spring.profiles.active=DEV -------------------------------------------------------------------------------- /src/main/resources/mapper/db1/UserDao.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/main/resources/mapper/db2/UserBakDao.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/main/resources/sql/user.sql: -------------------------------------------------------------------------------- 1 | create table user 2 | ( 3 | id varchar(50) not null 4 | primary key, 5 | user_name varchar(50) null, 6 | login_name varchar(50) null, 7 | passwd varchar(50) null, 8 | dept_id varchar(50) null 9 | )charset=utf8mb4; 10 | 11 | -------------------------------------------------------------------------------- /src/test/java/com/lishuangqi/BigServerApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.lishuangqi; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class BigServerApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | --------------------------------------------------------------------------------