(本篇博客已於2019-08-28優化更新)mysql
序言:這個讀寫分離摘自於Springboot多數據源快速啓動器,讀寫分離的話並非按照傳統方式的springmvc看方法命名那樣,而是在每一個方法上加註解或者類上添加註解代表選用的數據源。支持事物!spring
勾選Web,Mysql,MyBatis三個模塊,最終建立springboot項目成功sql
<!-- springboot-aop包,AOP切面註解,Aspectd等相關注解 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <version>1.0.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency>
server.port=8088 #數據源1 spring.datasource.db1.jdbc-url=jdbc:mysql://127.0.0.1:3306/test_msg2?useUnicode=true&characterEncoding=utf-8&useSSL=false spring.datasource.db1.username=root spring.datasource.db1.password=root spring.datasource.db1.driver-class-name=com.mysql.jdbc.Driver spring.datasource.db1.max-idle=10 spring.datasource.db1.max-wait=10000 spring.datasource.db1.min-idle=5 spring.datasource.db1.initial-size=5 #數據源2 spring.datasource.db2.jdbc-url=jdbc:mysql://127.0.0.1:3306/test_msg3?useUnicode=true&characterEncoding=utf-8&useSSL=false spring.datasource.db2.username=root spring.datasource.db2.password=root spring.datasource.db2.driver-class-name=com.mysql.jdbc.Driver spring.datasource.db2.max-idle=10 spring.datasource.db2.max-wait=10000 spring.datasource.db2.min-idle=5 spring.datasource.db2.initial-size=5 #mybatis mybatis.mapper-locations=classpath*:mapper/*.xml mybatis.type-aliases-package=com.springboot2.mjt04.dao
public class User { private int id; private String name; private int age; public User(){} public User(String name, int age){ this.name = name; this.age = age; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
<?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="com.springboot2.mjt04.dao.UserDao"> <!-- 查詢全部user --> <select id="getAllUser" resultType="java.util.Map"> select * from user </select> <!-- 添加數據並返回主鍵ID,接收主鍵,必須以實體類接收 --> <!-- keyColumn="id"對應數據庫字段,keyProperty="id"對應實體類屬性 --> <insert id="addUserGetID" parameterType="com.springboot2.mjt04.entity.User" useGeneratedKeys="true" keyColumn="id" keyProperty="id"> insert into user(name,age) values(#{name},#{age}) </insert> <insert id="addUser"> insert into user(name,age) values(#{name},#{age}) </insert> </mapper>
@Mapper public interface UserDao { //使用xml配置形式查詢 List<Map> getAllUser(); Long addUserGetID(User user); void addUser(User user); }
@Service public class UserService { @Autowired private UserDao moredataDao; //使用數據源1查詢 @DS("datasource1") public List<Map> getAllUser1(){ return moredataDao.getAllUser(); } //使用數據源2查詢 @DS("datasource2") public List<Map> getAllUser2(){ return moredataDao.getAllUser(); } //使用數據源1插入數據 @DS("datasource1") public Long addUserGetID1(User user){ return moredataDao.addUserGetID(user); } //使用數據源1插入數據 @DS("datasource2") public Long addUserGetID2(User user){ return moredataDao.addUserGetID(user); } //使用數據源1插入數據 @DS("datasource1") public void addUser1(User user){ moredataDao.addUser(user); } //使用數據源2插入數據 @DS("datasource2") public void addUser2(User user){ moredataDao.addUser(user); } @Transactional public void test1(){ moredataDao.addUserGetID(new User("mdx1",18)); int a =10/0; moredataDao.addUserGetID(new User("mdxl1",20)); } }
@Controller public class RWController { @Autowired UserService userService; //走數據源1庫 @GetMapping(value = "/test1") @ResponseBody public String testOne(){ User user = new User("mjt01",20); userService.addUser1(user); return "success"; } //使用數據源2插入數據 @GetMapping(value = "/test2") @ResponseBody public String testTwo(){ User user = new User("mjt02",20); userService.addUser2(user); return "success"; } }
5個配置文件,切記若是照着寫的話,當心裏面的路徑要準確對應上數據庫
//import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.PlatformTransactionManager; import javax.sql.DataSource; import java.util.HashMap; import java.util.Map; /** * 多數據源配置類 * Created by pure on 2018-05-06. */ @Configuration public class DataSourceConfig { //數據源1 @Bean(name = "datasource1") @ConfigurationProperties(prefix = "spring.datasource.db1") // application.properteis中對應屬性的前綴 public DataSource dataSource1() { return DataSourceBuilder.create().build(); } //數據源2 @Bean(name = "datasource2") @ConfigurationProperties(prefix = "spring.datasource.db2") // application.properteis中對應屬性的前綴 public DataSource dataSource2() { return DataSourceBuilder.create().build(); } /** * 動態數據源: 經過AOP在不一樣數據源之間動態切換 * @return */ @Primary @Bean(name = "dynamicDataSource") public DataSource dynamicDataSource() { DynamicDataSource dynamicDataSource = new DynamicDataSource(); // 默認數據源 dynamicDataSource.setDefaultTargetDataSource(dataSource1()); // 配置多數據源 Map<Object, Object> dsMap = new HashMap(); dsMap.put("datasource1", dataSource1()); dsMap.put("datasource2", dataSource2()); dynamicDataSource.setTargetDataSources(dsMap); return dynamicDataSource; } /** * 配置@Transactional註解事物 * @return */ @Bean public PlatformTransactionManager transactionManager() { return new DataSourceTransactionManager(dynamicDataSource()); } }
public class DataSourceContextHolder { /** * 默認數據源 */ public static final String DEFAULT_DS = "datasource1"; private static final ThreadLocal<String> contextHolder = new ThreadLocal<>(); // 設置數據源名 public static void setDB(String dbType) { System.out.println("切換到{"+dbType+"}數據源"); contextHolder.set(dbType); } // 獲取數據源名 public static String getDB() { return (contextHolder.get()); } // 清除數據源名 public static void clearDB() { contextHolder.remove(); } }
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) public @interface DS { String value() default "datasource1"; }
public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { System.out.println("數據源爲"+DataSourceContextHolder.getDB()); return DataSourceContextHolder.getDB(); } }
@Aspect @Component public class DynamicDataSourceAspect { @Before("@annotation(com.springboot2.mjt04.config.mysql.DS)") public void beforeSwitchDS(JoinPoint point){ //得到當前訪問的class Class<?> className = point.getTarget().getClass(); //得到訪問的方法名 String methodName = point.getSignature().getName(); //獲得方法的參數的類型 Class[] argClass = ((MethodSignature)point.getSignature()).getParameterTypes(); String dataSource = DataSourceContextHolder.DEFAULT_DS; try { // 獲得訪問的方法對象 Method method = className.getMethod(methodName, argClass); // 判斷是否存在@DS註解 if (method.isAnnotationPresent(DS.class)) { DS annotation = method.getAnnotation(DS.class); // 取出註解中的數據源名 dataSource = annotation.value(); } } catch (Exception e) { e.printStackTrace(); } // 切換數據源 DataSourceContextHolder.setDB(dataSource); } @After("@annotation(com.springboot2.mjt04.config.mysql.DS)") public void afterSwitchDS(JoinPoint point){ DataSourceContextHolder.clearDB(); } }
最終目錄結構圖:springboot
10.1 出現這個錯誤 jdbcUrl is required with driverClassName.運行出現這個過程是由於在多數據源的狀況下,springboot2.0與1.X版本都不一樣配置屬性,解決jdbcUrl is required with driverClassName.問題,點擊這裏,可是我如今已經改過來了,之前是mybatis
spring.datasource.db1.url=jdbc:mysql://127.0.0.1:3306/test_msg2?useUnicode=true&characterEncoding=utf-8&useSSL=false
而如今添加了jdbc-urlmvc
spring.datasource.db1.jdbc-url=jdbc:mysql://127.0.0.1:3306/test_msg2?useUnicode=true&characterEncoding=utf-8&useSSL=false
10.2 包名路徑跟換app
之前1.X版本爲ide
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
而如今2.X版本
import org.springframework.boot.jdbc.DataSourceBuilder;
注意一下就好,由於我都給你們改好了。
5.3 事物能夠正常使用,也支持讀寫分離,不過在事物的方法可能比springmvc的項目麻煩些,畢竟目前個人技術只能用註解才能切換數據源,目前我沒有成功找到在配置類根據方法前綴名就能夠判斷數據源的。
5.4 這個是application啓動類上面的一個註解,代表是不使用DataSourceAutoCOnfiguration.class,由於咱們的是多個數據源,不能默認使用一個單數據源,因此要加上這個。
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
成功!不懂能夠私信我或者留言就好。