style(all): 使用IDEA默认的格式化方案

This commit is contained in:
小锅盖 2020-05-20 17:56:16 +08:00
parent 07a5419a5c
commit 89a4ffae18
117 changed files with 3588 additions and 3556 deletions

View File

@ -6,8 +6,8 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication @SpringBootApplication
public class LoadApplication { public class LoadApplication {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(LoadApplication.class, args); SpringApplication.run(LoadApplication.class, args);
} }
} }

View File

@ -13,13 +13,13 @@ import springfox.documentation.swagger2.annotations.EnableSwagger2;
@EnableSwagger2 @EnableSwagger2
public class SwaggerAutoConfig { public class SwaggerAutoConfig {
@Bean @Bean
public Docket api() { public Docket api() {
return new Docket(DocumentationType.SWAGGER_2) return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(ApiInfo.DEFAULT) .apiInfo(ApiInfo.DEFAULT)
.select() .select()
.apis(RequestHandlerSelectors.basePackage("com.baomidou.samples.dynamicload.controller")) .apis(RequestHandlerSelectors.basePackage("com.baomidou.samples.dynamicload.controller"))
.paths(PathSelectors.any()) .paths(PathSelectors.any())
.build(); .build();
} }
} }

View File

@ -1,26 +1,18 @@
package com.baomidou.samples.dynamicload.controller; package com.baomidou.samples.dynamicload.controller;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.creator.BasicDataSourceCreator; import com.baomidou.dynamic.datasource.creator.*;
import com.baomidou.dynamic.datasource.creator.DataSourceCreator;
import com.baomidou.dynamic.datasource.creator.DruidDataSourceCreator;
import com.baomidou.dynamic.datasource.creator.HikariDataSourceCreator;
import com.baomidou.dynamic.datasource.creator.JndiDataSourceCreator;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty; import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import com.baomidou.samples.dynamicload.dto.DataSourceDTO; import com.baomidou.samples.dynamicload.dto.DataSourceDTO;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import java.util.Set;
import javax.sql.DataSource;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import javax.sql.DataSource;
import org.springframework.web.bind.annotation.RequestBody; import java.util.Set;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController @RestController
@AllArgsConstructor @AllArgsConstructor
@ -28,78 +20,78 @@ import org.springframework.web.bind.annotation.RestController;
@Api(tags = "添加删除数据源") @Api(tags = "添加删除数据源")
public class LoadController { public class LoadController {
private final DataSource dataSource; private final DataSource dataSource;
private final DataSourceCreator dataSourceCreator; private final DataSourceCreator dataSourceCreator;
private final BasicDataSourceCreator basicDataSourceCreator; private final BasicDataSourceCreator basicDataSourceCreator;
private final JndiDataSourceCreator jndiDataSourceCreator; private final JndiDataSourceCreator jndiDataSourceCreator;
private final DruidDataSourceCreator druidDataSourceCreator; private final DruidDataSourceCreator druidDataSourceCreator;
private final HikariDataSourceCreator hikariDataSourceCreator; private final HikariDataSourceCreator hikariDataSourceCreator;
@GetMapping @GetMapping
@ApiOperation("获取当前所有数据源") @ApiOperation("获取当前所有数据源")
public Set<String> now() { public Set<String> now() {
DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource; DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
return ds.getCurrentDataSources().keySet(); return ds.getCurrentDataSources().keySet();
} }
@PostMapping("/add") @PostMapping("/add")
@ApiOperation("通用添加数据源(推荐)") @ApiOperation("通用添加数据源(推荐)")
public Set<String> add(@Validated @RequestBody DataSourceDTO dto) { public Set<String> add(@Validated @RequestBody DataSourceDTO dto) {
DataSourceProperty dataSourceProperty = new DataSourceProperty(); DataSourceProperty dataSourceProperty = new DataSourceProperty();
BeanUtils.copyProperties(dto, dataSourceProperty); BeanUtils.copyProperties(dto, dataSourceProperty);
DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource; DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
DataSource dataSource = dataSourceCreator.createDataSource(dataSourceProperty); DataSource dataSource = dataSourceCreator.createDataSource(dataSourceProperty);
ds.addDataSource(dto.getPollName(), dataSource); ds.addDataSource(dto.getPollName(), dataSource);
return ds.getCurrentDataSources().keySet(); return ds.getCurrentDataSources().keySet();
} }
@PostMapping("/addBasic") @PostMapping("/addBasic")
@ApiOperation(value = "添加基础数据源", notes = "调用Springboot内置方法创建数据源兼容1,2") @ApiOperation(value = "添加基础数据源", notes = "调用Springboot内置方法创建数据源兼容1,2")
public Set<String> addBasic(@Validated @RequestBody DataSourceDTO dto) { public Set<String> addBasic(@Validated @RequestBody DataSourceDTO dto) {
DataSourceProperty dataSourceProperty = new DataSourceProperty(); DataSourceProperty dataSourceProperty = new DataSourceProperty();
BeanUtils.copyProperties(dto, dataSourceProperty); BeanUtils.copyProperties(dto, dataSourceProperty);
DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource; DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
DataSource dataSource = basicDataSourceCreator.createDataSource(dataSourceProperty); DataSource dataSource = basicDataSourceCreator.createDataSource(dataSourceProperty);
ds.addDataSource(dto.getPollName(), dataSource); ds.addDataSource(dto.getPollName(), dataSource);
return ds.getCurrentDataSources().keySet(); return ds.getCurrentDataSources().keySet();
} }
@PostMapping("/addJndi") @PostMapping("/addJndi")
@ApiOperation("添加JNDI数据源") @ApiOperation("添加JNDI数据源")
public Set<String> addJndi(String pollName, String jndiName) { public Set<String> addJndi(String pollName, String jndiName) {
DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource; DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
DataSource dataSource = jndiDataSourceCreator.createDataSource(jndiName); DataSource dataSource = jndiDataSourceCreator.createDataSource(jndiName);
ds.addDataSource(pollName, dataSource); ds.addDataSource(pollName, dataSource);
return ds.getCurrentDataSources().keySet(); return ds.getCurrentDataSources().keySet();
} }
@PostMapping("/addDruid") @PostMapping("/addDruid")
@ApiOperation("基础Druid数据源") @ApiOperation("基础Druid数据源")
public Set<String> addDruid(@Validated @RequestBody DataSourceDTO dto) { public Set<String> addDruid(@Validated @RequestBody DataSourceDTO dto) {
DataSourceProperty dataSourceProperty = new DataSourceProperty(); DataSourceProperty dataSourceProperty = new DataSourceProperty();
BeanUtils.copyProperties(dto, dataSourceProperty); BeanUtils.copyProperties(dto, dataSourceProperty);
DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource; DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
DataSource dataSource = druidDataSourceCreator.createDataSource(dataSourceProperty); DataSource dataSource = druidDataSourceCreator.createDataSource(dataSourceProperty);
ds.addDataSource(dto.getPollName(), dataSource); ds.addDataSource(dto.getPollName(), dataSource);
return ds.getCurrentDataSources().keySet(); return ds.getCurrentDataSources().keySet();
} }
@PostMapping("/addHikariCP") @PostMapping("/addHikariCP")
@ApiOperation("基础HikariCP数据源") @ApiOperation("基础HikariCP数据源")
public Set<String> addHikariCP(@Validated @RequestBody DataSourceDTO dto) { public Set<String> addHikariCP(@Validated @RequestBody DataSourceDTO dto) {
DataSourceProperty dataSourceProperty = new DataSourceProperty(); DataSourceProperty dataSourceProperty = new DataSourceProperty();
BeanUtils.copyProperties(dto, dataSourceProperty); BeanUtils.copyProperties(dto, dataSourceProperty);
DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource; DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
DataSource dataSource = hikariDataSourceCreator.createDataSource(dataSourceProperty); DataSource dataSource = hikariDataSourceCreator.createDataSource(dataSourceProperty);
ds.addDataSource(dto.getPollName(), dataSource); ds.addDataSource(dto.getPollName(), dataSource);
return ds.getCurrentDataSources().keySet(); return ds.getCurrentDataSources().keySet();
} }
@DeleteMapping @DeleteMapping
@ApiOperation("删除数据源") @ApiOperation("删除数据源")
public String remove(String name) { public String remove(String name) {
DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource; DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
ds.removeDataSource(name); ds.removeDataSource(name);
return "删除成功"; return "删除成功";
} }
} }

View File

@ -1,9 +1,10 @@
package com.baomidou.samples.dynamicload.dto; package com.baomidou.samples.dynamicload.dto;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import javax.validation.constraints.NotBlank;
import lombok.Data; import lombok.Data;
import javax.validation.constraints.NotBlank;
/** /**
* @author TaoYu * @author TaoYu
* @date 2020/1/27 * @date 2020/1/27
@ -11,23 +12,23 @@ import lombok.Data;
@Data @Data
public class DataSourceDTO { public class DataSourceDTO {
@NotBlank @NotBlank
@ApiModelProperty(value = "连接池名称", example = "test") @ApiModelProperty(value = "连接池名称", example = "test")
private String pollName; private String pollName;
@NotBlank @NotBlank
@ApiModelProperty(value = "JDBC driver", example = "org.h2.Driver") @ApiModelProperty(value = "JDBC driver", example = "org.h2.Driver")
private String driverClassName; private String driverClassName;
@NotBlank @NotBlank
@ApiModelProperty(value = "JDBC url 地址", example = "jdbc:h2:mem:test10") @ApiModelProperty(value = "JDBC url 地址", example = "jdbc:h2:mem:test10")
private String url; private String url;
@NotBlank @NotBlank
@ApiModelProperty(value = "JDBC 用户名", example = "sa") @ApiModelProperty(value = "JDBC 用户名", example = "sa")
private String username; private String username;
@ApiModelProperty(value = "JDBC 密码") @ApiModelProperty(value = "JDBC 密码")
private String password; private String password;
} }

View File

@ -9,8 +9,8 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
@MapperScan("com.baomidou.samples.druid.mybatis.mapper") @MapperScan("com.baomidou.samples.druid.mybatis.mapper")
public class DruidMybatisApplication { public class DruidMybatisApplication {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(DruidMybatisApplication.class, args); SpringApplication.run(DruidMybatisApplication.class, args);
} }
} }

View File

@ -2,33 +2,33 @@ package com.baomidou.samples.druid.mybatis.entity;
public class User { public class User {
private Integer id; private Integer id;
private String name; private String name;
private Integer age; private Integer age;
public Integer getId() { public Integer getId() {
return id; return id;
} }
public void setId(Integer id) { public void setId(Integer id) {
this.id = id; this.id = id;
} }
public String getName() { public String getName() {
return name; return name;
} }
public void setName(String name) { public void setName(String name) {
this.name = name; this.name = name;
} }
public Integer getAge() { public Integer getAge() {
return age; return age;
} }
public void setAge(Integer age) { public void setAge(Integer age) {
this.age = age; this.age = age;
} }
} }

View File

@ -1,16 +1,17 @@
package com.baomidou.samples.druid.mybatis.mapper; package com.baomidou.samples.druid.mybatis.mapper;
import com.baomidou.samples.druid.mybatis.entity.User; import com.baomidou.samples.druid.mybatis.entity.User;
import java.util.List;
import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface UserMapper { public interface UserMapper {
@Insert("INSERT INTO user (name,age) values (#{name},#{age})") @Insert("INSERT INTO user (name,age) values (#{name},#{age})")
boolean addUser(@Param("name") String name, @Param("age") Integer age); boolean addUser(@Param("name") String name, @Param("age") Integer age);
@Select("SELECT * FROM user where age > #{age}") @Select("SELECT * FROM user where age > #{age}")
List<User> selectUsers(@Param("age") Integer age); List<User> selectUsers(@Param("age") Integer age);
} }

View File

@ -2,13 +2,14 @@ package com.baomidou.samples.druid.mybatis.service;
import com.baomidou.samples.druid.mybatis.entity.User; import com.baomidou.samples.druid.mybatis.entity.User;
import java.util.List; import java.util.List;
public interface UserService { public interface UserService {
void addUser(User user); void addUser(User user);
List selectUsersFromDs(); List selectUsersFromDs();
List selectUserFromDsGroup(); List selectUserFromDsGroup();
} }

View File

@ -5,30 +5,31 @@ import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.samples.druid.mybatis.entity.User; import com.baomidou.samples.druid.mybatis.entity.User;
import com.baomidou.samples.druid.mybatis.mapper.UserMapper; import com.baomidou.samples.druid.mybatis.mapper.UserMapper;
import com.baomidou.samples.druid.mybatis.service.UserService; import com.baomidou.samples.druid.mybatis.service.UserService;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service @Service
public class UserServiceImpl implements UserService { public class UserServiceImpl implements UserService {
@Resource @Resource
private UserMapper userMapper; private UserMapper userMapper;
@Override @Override
public void addUser(User user) { public void addUser(User user) {
userMapper.addUser(user.getName(), user.getAge()); userMapper.addUser(user.getName(), user.getAge());
} }
@DS("slave_1") @DS("slave_1")
@Override @Override
public List selectUsersFromDs() { public List selectUsersFromDs() {
return userMapper.selectUsers(1); return userMapper.selectUsers(1);
} }
@DS("slave") @DS("slave")
@Override @Override
public List selectUserFromDsGroup() { public List selectUserFromDsGroup() {
return userMapper.selectUsers(1); return userMapper.selectUsers(1);
} }
} }

View File

@ -3,38 +3,39 @@ package com.baomidou.samples.druid.mybatis.test;
import com.baomidou.samples.druid.mybatis.DruidMybatisApplication; import com.baomidou.samples.druid.mybatis.DruidMybatisApplication;
import com.baomidou.samples.druid.mybatis.entity.User; import com.baomidou.samples.druid.mybatis.entity.User;
import com.baomidou.samples.druid.mybatis.service.UserService; import com.baomidou.samples.druid.mybatis.service.UserService;
import java.util.Random;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.junit4.SpringRunner;
import java.util.Random;
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
@SpringBootTest(classes = DruidMybatisApplication.class) @SpringBootTest(classes = DruidMybatisApplication.class)
public class DruidMybatisApplicationTest { public class DruidMybatisApplicationTest {
private Random random = new Random(); private Random random = new Random();
@Autowired @Autowired
private UserService userService; private UserService userService;
@Test @Test
public void addUser() { public void addUser() {
User user = new User(); User user = new User();
user.setName("测试用户" + random.nextInt()); user.setName("测试用户" + random.nextInt());
user.setAge(random.nextInt(100)); user.setAge(random.nextInt(100));
userService.addUser(user); userService.addUser(user);
} }
@Test @Test
public void selectUsersFromDs() { public void selectUsersFromDs() {
userService.selectUsersFromDs(); userService.selectUsersFromDs();
} }
@Test @Test
public void selectUserFromDsGroup() { public void selectUserFromDsGroup() {
userService.selectUserFromDsGroup(); userService.selectUserFromDsGroup();
} }
} }

View File

@ -1,21 +1,22 @@
package com.baomidou.samples.jdbc; package com.baomidou.samples.jdbc;
import javax.sql.DataSource;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;
@SpringBootApplication @SpringBootApplication
public class Application { public class Application {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(Application.class, args); SpringApplication.run(Application.class, args);
} }
@Bean @Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) { public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource); return new JdbcTemplate(dataSource);
} }
} }

View File

@ -2,33 +2,33 @@ package com.baomidou.samples.jdbc.entity;
public class User { public class User {
private Integer id; private Integer id;
private String name; private String name;
private Integer age; private Integer age;
public Integer getId() { public Integer getId() {
return id; return id;
} }
public void setId(Integer id) { public void setId(Integer id) {
this.id = id; this.id = id;
} }
public String getName() { public String getName() {
return name; return name;
} }
public void setName(String name) { public void setName(String name) {
this.name = name; this.name = name;
} }
public Integer getAge() { public Integer getAge() {
return age; return age;
} }
public void setAge(Integer age) { public void setAge(Integer age) {
this.age = age; this.age = age;
} }
} }

View File

@ -1,13 +1,14 @@
package com.baomidou.samples.jdbc.service; package com.baomidou.samples.jdbc.service;
import com.baomidou.samples.jdbc.entity.User; import com.baomidou.samples.jdbc.entity.User;
import java.util.List; import java.util.List;
public interface UserService { public interface UserService {
void addUser(User user); void addUser(User user);
List selectUsersFromDs(); List selectUsersFromDs();
List selectUserFromDsGroup(); List selectUserFromDsGroup();
} }

View File

@ -4,32 +4,33 @@ package com.baomidou.samples.jdbc.service.impl;
import com.baomidou.dynamic.datasource.annotation.DS; import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.samples.jdbc.entity.User; import com.baomidou.samples.jdbc.entity.User;
import com.baomidou.samples.jdbc.service.UserService; import com.baomidou.samples.jdbc.service.UserService;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.List;
@Service @Service
public class UserServiceImpl implements UserService { public class UserServiceImpl implements UserService {
@Autowired @Autowired
private JdbcTemplate jdbcTemplate; private JdbcTemplate jdbcTemplate;
@Override @Override
public void addUser(User user) { public void addUser(User user) {
jdbcTemplate.update("INSERT INTO user (name,age) VALUES(?, ?)", jdbcTemplate.update("INSERT INTO user (name,age) VALUES(?, ?)",
new Object[]{user.getName(), user.getAge()}); new Object[]{user.getName(), user.getAge()});
} }
@DS("slave_1") @DS("slave_1")
@Override @Override
public List selectUsersFromDs() { public List selectUsersFromDs() {
return jdbcTemplate.queryForList("SELECT * FROM user"); return jdbcTemplate.queryForList("SELECT * FROM user");
} }
@DS("slave") @DS("slave")
@Override @Override
public List selectUserFromDsGroup() { public List selectUserFromDsGroup() {
return jdbcTemplate.queryForList("SELECT * FROM user"); return jdbcTemplate.queryForList("SELECT * FROM user");
} }
} }

View File

@ -3,37 +3,38 @@ package com.baomidou.samples.jdbc.test;
import com.baomidou.samples.jdbc.Application; import com.baomidou.samples.jdbc.Application;
import com.baomidou.samples.jdbc.entity.User; import com.baomidou.samples.jdbc.entity.User;
import com.baomidou.samples.jdbc.service.UserService; import com.baomidou.samples.jdbc.service.UserService;
import java.util.Random;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.junit4.SpringRunner;
import java.util.Random;
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class) @SpringBootTest(classes = Application.class)
public class ApplicationTest { public class ApplicationTest {
private Random random = new Random(); private Random random = new Random();
@Autowired @Autowired
private UserService userService; private UserService userService;
@Test @Test
public void addUser() { public void addUser() {
User user = new User(); User user = new User();
user.setName("测试用户" + random.nextInt()); user.setName("测试用户" + random.nextInt());
user.setAge(random.nextInt(100)); user.setAge(random.nextInt(100));
userService.addUser(user); userService.addUser(user);
} }
@Test @Test
public void selectUsersFromDs() { public void selectUsersFromDs() {
userService.selectUsersFromDs(); userService.selectUsersFromDs();
} }
@Test @Test
public void selectUserFromDsGroup() { public void selectUserFromDsGroup() {
userService.selectUserFromDsGroup(); userService.selectUserFromDsGroup();
} }
} }

View File

@ -8,8 +8,8 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
@MapperScan("com.baomidou.samples.mybatis.mapper") @MapperScan("com.baomidou.samples.mybatis.mapper")
public class Application { public class Application {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(Application.class, args); SpringApplication.run(Application.class, args);
} }
} }

View File

@ -2,33 +2,33 @@ package com.baomidou.samples.mybatis.entity;
public class User { public class User {
private Integer id; private Integer id;
private String name; private String name;
private Integer age; private Integer age;
public Integer getId() { public Integer getId() {
return id; return id;
} }
public void setId(Integer id) { public void setId(Integer id) {
this.id = id; this.id = id;
} }
public String getName() { public String getName() {
return name; return name;
} }
public void setName(String name) { public void setName(String name) {
this.name = name; this.name = name;
} }
public Integer getAge() { public Integer getAge() {
return age; return age;
} }
public void setAge(Integer age) { public void setAge(Integer age) {
this.age = age; this.age = age;
} }
} }

View File

@ -1,17 +1,18 @@
package com.baomidou.samples.mybatis.mapper; package com.baomidou.samples.mybatis.mapper;
import com.baomidou.samples.mybatis.entity.User; import com.baomidou.samples.mybatis.entity.User;
import java.util.List;
import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Select;
import java.util.List;
//@DS("slave")这里可以使用但不建议不要和service同时使用 //@DS("slave")这里可以使用但不建议不要和service同时使用
public interface UserMapper { public interface UserMapper {
@Insert("INSERT INTO user (name,age) values (#{name},#{age})") @Insert("INSERT INTO user (name,age) values (#{name},#{age})")
boolean addUser(@Param("name") String name, @Param("age") Integer age); boolean addUser(@Param("name") String name, @Param("age") Integer age);
@Select("SELECT * FROM user") @Select("SELECT * FROM user")
List<User> selectUsers(); List<User> selectUsers();
} }

View File

@ -2,13 +2,14 @@ package com.baomidou.samples.mybatis.service;
import com.baomidou.samples.mybatis.entity.User; import com.baomidou.samples.mybatis.entity.User;
import java.util.List; import java.util.List;
public interface UserService { public interface UserService {
void addUser(User user); void addUser(User user);
List selectUsersFromDs(); List selectUsersFromDs();
List selectUserFromDsGroup(); List selectUserFromDsGroup();
} }

View File

@ -5,30 +5,31 @@ import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.samples.mybatis.entity.User; import com.baomidou.samples.mybatis.entity.User;
import com.baomidou.samples.mybatis.mapper.UserMapper; import com.baomidou.samples.mybatis.mapper.UserMapper;
import com.baomidou.samples.mybatis.service.UserService; import com.baomidou.samples.mybatis.service.UserService;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service @Service
public class UserServiceImpl implements UserService { public class UserServiceImpl implements UserService {
@Resource @Resource
private UserMapper userMapper; private UserMapper userMapper;
@Override @Override
public void addUser(User user) { public void addUser(User user) {
userMapper.addUser(user.getName(), user.getAge()); userMapper.addUser(user.getName(), user.getAge());
} }
@DS("slave_1") @DS("slave_1")
@Override @Override
public List selectUsersFromDs() { public List selectUsersFromDs() {
return userMapper.selectUsers(); return userMapper.selectUsers();
} }
@DS("slave") @DS("slave")
@Override @Override
public List selectUserFromDsGroup() { public List selectUserFromDsGroup() {
return userMapper.selectUsers(); return userMapper.selectUsers();
} }
} }

View File

@ -4,37 +4,38 @@ package com.baomidou.samples.mybatis.test;
import com.baomidou.samples.mybatis.Application; import com.baomidou.samples.mybatis.Application;
import com.baomidou.samples.mybatis.entity.User; import com.baomidou.samples.mybatis.entity.User;
import com.baomidou.samples.mybatis.service.UserService; import com.baomidou.samples.mybatis.service.UserService;
import java.util.Random;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.junit4.SpringRunner;
import java.util.Random;
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class) @SpringBootTest(classes = Application.class)
public class ApplicationTest { public class ApplicationTest {
private Random random = new Random(); private Random random = new Random();
@Autowired @Autowired
private UserService userService; private UserService userService;
@Test @Test
public void addUser() { public void addUser() {
User user = new User(); User user = new User();
user.setName("测试用户" + random.nextInt()); user.setName("测试用户" + random.nextInt());
user.setAge(random.nextInt(100)); user.setAge(random.nextInt(100));
userService.addUser(user); userService.addUser(user);
} }
@Test @Test
public void selectUsersFromDs() { public void selectUsersFromDs() {
userService.selectUsersFromDs(); userService.selectUsersFromDs();
} }
@Test @Test
public void selectUserFromDsGroup() { public void selectUserFromDsGroup() {
userService.selectUserFromDsGroup(); userService.selectUserFromDsGroup();
} }
} }

View File

@ -8,8 +8,8 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
@MapperScan("com.baomidou.samples.mybatisplus2.mapper") @MapperScan("com.baomidou.samples.mybatisplus2.mapper")
public class Application { public class Application {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(Application.class, args); SpringApplication.run(Application.class, args);
} }
} }

View File

@ -5,34 +5,34 @@ import com.baomidou.mybatisplus.enums.IdType;
public class User { public class User {
@TableId(type = IdType.AUTO) @TableId(type = IdType.AUTO)
private Integer id; private Integer id;
private String name; private String name;
private Integer age; private Integer age;
public Integer getId() { public Integer getId() {
return id; return id;
} }
public void setId(Integer id) { public void setId(Integer id) {
this.id = id; this.id = id;
} }
public String getName() { public String getName() {
return name; return name;
} }
public void setName(String name) { public void setName(String name) {
this.name = name; this.name = name;
} }
public Integer getAge() { public Integer getAge() {
return age; return age;
} }
public void setAge(Integer age) { public void setAge(Integer age) {
this.age = age; this.age = age;
} }
} }

View File

@ -6,6 +6,6 @@ import com.baomidou.samples.mybatisplus2.entity.User;
public interface UserService extends IService<User> { public interface UserService extends IService<User> {
void addUser(User user); void addUser(User user);
} }

View File

@ -12,9 +12,9 @@ import org.springframework.stereotype.Service;
@DS("slave") @DS("slave")
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService { public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
@Override @Override
// @DS("master")//这里必须包一层不能调用mp默认的插入因为会走到从库去 // @DS("master")//这里必须包一层不能调用mp默认的插入因为会走到从库去
public void addUser(User user) { public void addUser(User user) {
baseMapper.insert(user); baseMapper.insert(user);
} }
} }

View File

@ -3,33 +3,34 @@ package com.baomidou.samples.mybatisplus2.test;
import com.baomidou.samples.mybatisplus2.Application; import com.baomidou.samples.mybatisplus2.Application;
import com.baomidou.samples.mybatisplus2.entity.User; import com.baomidou.samples.mybatisplus2.entity.User;
import com.baomidou.samples.mybatisplus2.service.UserService; import com.baomidou.samples.mybatisplus2.service.UserService;
import java.util.Random;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.junit4.SpringRunner;
import java.util.Random;
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class) @SpringBootTest(classes = Application.class)
public class ApplicationTest { public class ApplicationTest {
private Random random = new Random(); private Random random = new Random();
@Autowired @Autowired
private UserService userService; private UserService userService;
@Test @Test
public void testAddUser() { public void testAddUser() {
User user = new User(); User user = new User();
user.setName("测试用户" + random.nextInt()); user.setName("测试用户" + random.nextInt());
user.setAge(random.nextInt(100)); user.setAge(random.nextInt(100));
userService.addUser(user); userService.addUser(user);
} }
@Test @Test
public void testSelectUser() { public void testSelectUser() {
userService.selectList(null); userService.selectList(null);
} }
} }

View File

@ -8,8 +8,8 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
@MapperScan("com.baomidou.samples.mybatisplus.mapper") @MapperScan("com.baomidou.samples.mybatisplus.mapper")
public class Application { public class Application {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(Application.class, args); SpringApplication.run(Application.class, args);
} }
} }

View File

@ -5,34 +5,34 @@ import com.baomidou.mybatisplus.annotation.TableId;
public class User { public class User {
@TableId(type = IdType.AUTO) @TableId(type = IdType.AUTO)
private Integer id; private Integer id;
private String name; private String name;
private Integer age; private Integer age;
public Integer getId() { public Integer getId() {
return id; return id;
} }
public void setId(Integer id) { public void setId(Integer id) {
this.id = id; this.id = id;
} }
public String getName() { public String getName() {
return name; return name;
} }
public void setName(String name) { public void setName(String name) {
this.name = name; this.name = name;
} }
public Integer getAge() { public Integer getAge() {
return age; return age;
} }
public void setAge(Integer age) { public void setAge(Integer age) {
this.age = age; this.age = age;
} }
} }

View File

@ -6,6 +6,6 @@ import com.baomidou.samples.mybatisplus.entity.User;
public interface UserService extends IService<User> { public interface UserService extends IService<User> {
void addUser(User user); void addUser(User user);
} }

View File

@ -12,9 +12,9 @@ import org.springframework.stereotype.Service;
@DS("slave") @DS("slave")
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService { public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
@Override @Override
@DS("master")//这里必须包一层不能调用mp默认的插入因为会走到从库去 @DS("master")//这里必须包一层不能调用mp默认的插入因为会走到从库去
public void addUser(User user) { public void addUser(User user) {
baseMapper.insert(user); baseMapper.insert(user);
} }
} }

View File

@ -3,32 +3,33 @@ package com.baomidou.samples.mybatisplus3.test;
import com.baomidou.samples.mybatisplus.Application; import com.baomidou.samples.mybatisplus.Application;
import com.baomidou.samples.mybatisplus.entity.User; import com.baomidou.samples.mybatisplus.entity.User;
import com.baomidou.samples.mybatisplus.service.UserService; import com.baomidou.samples.mybatisplus.service.UserService;
import java.util.Random;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.junit4.SpringRunner;
import java.util.Random;
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class) @SpringBootTest(classes = Application.class)
public class ApplicationTest { public class ApplicationTest {
private Random random = new Random(); private Random random = new Random();
@Autowired @Autowired
private UserService userService; private UserService userService;
@Test @Test
public void testAddUser() { public void testAddUser() {
User user = new User(); User user = new User();
user.setName("测试用户" + random.nextInt()); user.setName("测试用户" + random.nextInt());
user.setAge(random.nextInt(100)); user.setAge(random.nextInt(100));
userService.addUser(user); userService.addUser(user);
} }
@Test @Test
public void testSelectUser() { public void testSelectUser() {
userService.list(null); userService.list(null);
} }
} }

View File

@ -8,8 +8,8 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
@MapperScan("com.baomidou.samples.nest.mapper") @MapperScan("com.baomidou.samples.nest.mapper")
public class Application { public class Application {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(Application.class, args); SpringApplication.run(Application.class, args);
} }
} }

View File

@ -1,38 +1,39 @@
package com.baomidou.samples.nest; package com.baomidou.samples.nest;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationStartedEvent; import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.ApplicationListener; import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
@Component @Component
public class CreateDatabaseOnStarted implements ApplicationListener<ApplicationStartedEvent> { public class CreateDatabaseOnStarted implements ApplicationListener<ApplicationStartedEvent> {
@Autowired @Autowired
private DataSource dataSource; private DataSource dataSource;
@Override @Override
public void onApplicationEvent(ApplicationStartedEvent event) { public void onApplicationEvent(ApplicationStartedEvent event) {
try { try {
Connection connection = dataSource.getConnection(); Connection connection = dataSource.getConnection();
connection.createStatement().execute("CREATE TABLE IF NOT EXISTS teacher (\n" + connection.createStatement().execute("CREATE TABLE IF NOT EXISTS teacher (\n" +
" id BIGINT(20) NOT NULL AUTO_INCREMENT,\n" + " id BIGINT(20) NOT NULL AUTO_INCREMENT,\n" +
" name VARCHAR(30) NULL DEFAULT NULL ,\n" + " name VARCHAR(30) NULL DEFAULT NULL ,\n" +
" age INT(11) NULL DEFAULT NULL ,\n" + " age INT(11) NULL DEFAULT NULL ,\n" +
" PRIMARY KEY (id)\n" + " PRIMARY KEY (id)\n" +
");"); ");");
connection.createStatement().execute("CREATE TABLE IF NOT EXISTS student (\n" + connection.createStatement().execute("CREATE TABLE IF NOT EXISTS student (\n" +
" id BIGINT(20) NOT NULL AUTO_INCREMENT,\n" + " id BIGINT(20) NOT NULL AUTO_INCREMENT,\n" +
" name VARCHAR(30) NULL DEFAULT NULL ,\n" + " name VARCHAR(30) NULL DEFAULT NULL ,\n" +
" age INT(11) NULL DEFAULT NULL ,\n" + " age INT(11) NULL DEFAULT NULL ,\n" +
" PRIMARY KEY (id)\n" + " PRIMARY KEY (id)\n" +
");"); ");");
connection.close(); connection.close();
} catch (SQLException e) { } catch (SQLException e) {
e.printStackTrace(); e.printStackTrace();
}
} }
}
} }

View File

@ -9,27 +9,27 @@ import org.springframework.web.bind.annotation.RestController;
@RestController @RestController
public class TestController { public class TestController {
@Autowired @Autowired
private TeacherService teacherService; private TeacherService teacherService;
@Autowired @Autowired
private SchoolService schoolService; private SchoolService schoolService;
@GetMapping("/tx1") @GetMapping("/tx1")
public void tx1() { public void tx1() {
//外层不加事物里面每个单独加事物支持不过感觉没毛用 //外层不加事物里面每个单独加事物支持不过感觉没毛用
schoolService.addTeacherAndStudent(); schoolService.addTeacherAndStudent();
} }
@GetMapping("/tx2") @GetMapping("/tx2")
public void tx2() { public void tx2() {
//外层加事物里面每个也加事物不支持!!其实只要加了事物就不支持多库 //外层加事物里面每个也加事物不支持!!其实只要加了事物就不支持多库
schoolService.addTeacherAndStudentWithTx(); schoolService.addTeacherAndStudentWithTx();
} }
@GetMapping("/tx3") @GetMapping("/tx3")
public void tx3() { public void tx3() {
//单独调用加事物单库支持 //单独调用加事物单库支持
teacherService.addTeacherWithTx("tt", 12); teacherService.addTeacherWithTx("tt", 12);
} }
} }

View File

@ -2,33 +2,33 @@ package com.baomidou.samples.nest.entiry;
public class Student { public class Student {
private Integer id; private Integer id;
private String name; private String name;
private Integer age; private Integer age;
public Integer getId() { public Integer getId() {
return id; return id;
} }
public void setId(Integer id) { public void setId(Integer id) {
this.id = id; this.id = id;
} }
public String getName() { public String getName() {
return name; return name;
} }
public void setName(String name) { public void setName(String name) {
this.name = name; this.name = name;
} }
public Integer getAge() { public Integer getAge() {
return age; return age;
} }
public void setAge(Integer age) { public void setAge(Integer age) {
this.age = age; this.age = age;
} }
} }

View File

@ -2,33 +2,33 @@ package com.baomidou.samples.nest.entiry;
public class Teacher { public class Teacher {
private Integer id; private Integer id;
private String name; private String name;
private Integer age; private Integer age;
public Integer getId() { public Integer getId() {
return id; return id;
} }
public void setId(Integer id) { public void setId(Integer id) {
this.id = id; this.id = id;
} }
public String getName() { public String getName() {
return name; return name;
} }
public void setName(String name) { public void setName(String name) {
this.name = name; this.name = name;
} }
public Integer getAge() { public Integer getAge() {
return age; return age;
} }
public void setAge(Integer age) { public void setAge(Integer age) {
this.age = age; this.age = age;
} }
} }

View File

@ -1,16 +1,17 @@
package com.baomidou.samples.nest.mapper; package com.baomidou.samples.nest.mapper;
import com.baomidou.samples.nest.entiry.Student; import com.baomidou.samples.nest.entiry.Student;
import java.util.List;
import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface StudentMapper { public interface StudentMapper {
@Insert("INSERT INTO student (name,age) values (#{name},#{age})") @Insert("INSERT INTO student (name,age) values (#{name},#{age})")
boolean addStudent(@Param("name") String name, @Param("age") Integer age); boolean addStudent(@Param("name") String name, @Param("age") Integer age);
@Select("SELECT * FROM student") @Select("SELECT * FROM student")
List<Student> selectStudents(); List<Student> selectStudents();
} }

View File

@ -1,16 +1,17 @@
package com.baomidou.samples.nest.mapper; package com.baomidou.samples.nest.mapper;
import com.baomidou.samples.nest.entiry.Teacher; import com.baomidou.samples.nest.entiry.Teacher;
import java.util.List;
import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface TeacherMapper { public interface TeacherMapper {
@Insert("INSERT INTO teacher (name,age) values (#{name},#{age})") @Insert("INSERT INTO teacher (name,age) values (#{name},#{age})")
boolean addTeacher(@Param("name") String name, @Param("age") Integer age); boolean addTeacher(@Param("name") String name, @Param("age") Integer age);
@Select("SELECT * FROM teacher") @Select("SELECT * FROM teacher")
List<Teacher> selectTeachers(); List<Teacher> selectTeachers();
} }

View File

@ -2,11 +2,11 @@ package com.baomidou.samples.nest.service;
public interface SchoolService { public interface SchoolService {
void selectTeachersAndStudents(); void selectTeachersAndStudents();
void selectTeachersInnerStudents(); void selectTeachersInnerStudents();
void addTeacherAndStudent(); void addTeacherAndStudent();
void addTeacherAndStudentWithTx(); void addTeacherAndStudentWithTx();
} }

View File

@ -1,14 +1,15 @@
package com.baomidou.samples.nest.service; package com.baomidou.samples.nest.service;
import com.baomidou.samples.nest.entiry.Student; import com.baomidou.samples.nest.entiry.Student;
import java.util.List; import java.util.List;
public interface StudentService { public interface StudentService {
boolean addStudentWithTx(String name, Integer age); boolean addStudentWithTx(String name, Integer age);
boolean addStudentNoTx(String name, Integer age); boolean addStudentNoTx(String name, Integer age);
List<Student> selectStudents(); List<Student> selectStudents();
} }

View File

@ -1,17 +1,18 @@
package com.baomidou.samples.nest.service; package com.baomidou.samples.nest.service;
import com.baomidou.samples.nest.entiry.Teacher; import com.baomidou.samples.nest.entiry.Teacher;
import java.util.List; import java.util.List;
public interface TeacherService { public interface TeacherService {
boolean addTeacherWithTx(String name, Integer age); boolean addTeacherWithTx(String name, Integer age);
boolean addTeacherNoTx(String name, Integer age); boolean addTeacherNoTx(String name, Integer age);
List<Teacher> selectTeachers(); List<Teacher> selectTeachers();
void selectTeachersInnerStudents(); void selectTeachersInnerStudents();
} }

View File

@ -10,33 +10,33 @@ import org.springframework.transaction.annotation.Transactional;
@Service @Service
public class SchoolServiceImpl implements SchoolService { public class SchoolServiceImpl implements SchoolService {
@Autowired @Autowired
private TeacherService teacherService; private TeacherService teacherService;
@Autowired @Autowired
private StudentService studentService; private StudentService studentService;
@Override @Override
public void selectTeachersAndStudents() { public void selectTeachersAndStudents() {
teacherService.selectTeachers(); teacherService.selectTeachers();
studentService.selectStudents(); studentService.selectStudents();
} }
@Override @Override
public void selectTeachersInnerStudents() { public void selectTeachersInnerStudents() {
teacherService.selectTeachersInnerStudents(); teacherService.selectTeachersInnerStudents();
} }
@Override @Override
public void addTeacherAndStudent() { public void addTeacherAndStudent() {
teacherService.addTeacherWithTx("ss", 1); teacherService.addTeacherWithTx("ss", 1);
studentService.addStudentWithTx("tt", 2); studentService.addStudentWithTx("tt", 2);
} }
@Override @Override
@Transactional @Transactional
public void addTeacherAndStudentWithTx() { public void addTeacherAndStudentWithTx() {
teacherService.addTeacherWithTx("ss", 1); teacherService.addTeacherWithTx("ss", 1);
studentService.addStudentWithTx("tt", 2); studentService.addStudentWithTx("tt", 2);
} }
} }

View File

@ -4,31 +4,32 @@ import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.samples.nest.entiry.Student; import com.baomidou.samples.nest.entiry.Student;
import com.baomidou.samples.nest.mapper.StudentMapper; import com.baomidou.samples.nest.mapper.StudentMapper;
import com.baomidou.samples.nest.service.StudentService; import com.baomidou.samples.nest.service.StudentService;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.List;
@Service @Service
@DS("student") @DS("student")
public class StudentServiceImpl implements StudentService { public class StudentServiceImpl implements StudentService {
@Resource @Resource
private StudentMapper studentMapper; private StudentMapper studentMapper;
@Override @Override
@Transactional @Transactional
public boolean addStudentWithTx(String name, Integer age) { public boolean addStudentWithTx(String name, Integer age) {
return studentMapper.addStudent(name, age); return studentMapper.addStudent(name, age);
} }
@Override @Override
public boolean addStudentNoTx(String name, Integer age) { public boolean addStudentNoTx(String name, Integer age) {
return studentMapper.addStudent(name, age); return studentMapper.addStudent(name, age);
} }
@Override @Override
public List<Student> selectStudents() { public List<Student> selectStudents() {
return studentMapper.selectStudents(); return studentMapper.selectStudents();
} }
} }

View File

@ -5,40 +5,41 @@ import com.baomidou.samples.nest.entiry.Teacher;
import com.baomidou.samples.nest.mapper.TeacherMapper; import com.baomidou.samples.nest.mapper.TeacherMapper;
import com.baomidou.samples.nest.service.StudentService; import com.baomidou.samples.nest.service.StudentService;
import com.baomidou.samples.nest.service.TeacherService; import com.baomidou.samples.nest.service.TeacherService;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.List;
@Service @Service
@DS("teacher") @DS("teacher")
public class TeacherServiceImpl implements TeacherService { public class TeacherServiceImpl implements TeacherService {
@Resource @Resource
private TeacherMapper teacherMapper; private TeacherMapper teacherMapper;
@Autowired @Autowired
private StudentService studentService; private StudentService studentService;
@Override @Override
@Transactional @Transactional
public boolean addTeacherWithTx(String name, Integer age) { public boolean addTeacherWithTx(String name, Integer age) {
return teacherMapper.addTeacher(name, age); return teacherMapper.addTeacher(name, age);
} }
@Override @Override
public boolean addTeacherNoTx(String name, Integer age) { public boolean addTeacherNoTx(String name, Integer age) {
return teacherMapper.addTeacher(name, age); return teacherMapper.addTeacher(name, age);
} }
@Override @Override
public List<Teacher> selectTeachers() { public List<Teacher> selectTeachers() {
return teacherMapper.selectTeachers(); return teacherMapper.selectTeachers();
} }
@Override @Override
public void selectTeachersInnerStudents() { public void selectTeachersInnerStudents() {
teacherMapper.selectTeachers(); teacherMapper.selectTeachers();
studentService.selectStudents(); studentService.selectStudents();
} }
} }

View File

@ -5,46 +5,47 @@ import com.baomidou.samples.nest.Application;
import com.baomidou.samples.nest.service.SchoolService; import com.baomidou.samples.nest.service.SchoolService;
import com.baomidou.samples.nest.service.StudentService; import com.baomidou.samples.nest.service.StudentService;
import com.baomidou.samples.nest.service.TeacherService; import com.baomidou.samples.nest.service.TeacherService;
import java.util.Random;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.junit4.SpringRunner;
import java.util.Random;
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class) @SpringBootTest(classes = Application.class)
public class ApplicationTest { public class ApplicationTest {
private Random random = new Random(); private Random random = new Random();
@Autowired @Autowired
private TeacherService teacherService; private TeacherService teacherService;
@Autowired @Autowired
private StudentService studentService; private StudentService studentService;
@Autowired @Autowired
private SchoolService schoolService; private SchoolService schoolService;
@Test @Test
public void nest1() { public void nest1() {
//直接在controller //直接在controller
teacherService.selectTeachers(); teacherService.selectTeachers();
studentService.selectStudents(); studentService.selectStudents();
} }
@Test @Test
public void nest2() { public void nest2() {
schoolService.selectTeachersAndStudents(); schoolService.selectTeachersAndStudents();
} }
@Test @Test
public void nest3() { public void nest3() {
schoolService.selectTeachersInnerStudents(); schoolService.selectTeachersInnerStudents();
} }
@Test @Test
public void tx() { public void tx() {
teacherService.selectTeachers(); teacherService.selectTeachers();
} }
} }

View File

@ -9,8 +9,8 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
@MapperScan("com.baomidou.samples.seata.dao") @MapperScan("com.baomidou.samples.seata.dao")
public class SeataApplication { public class SeataApplication {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(SeataApplication.class, args); SpringApplication.run(SeataApplication.class, args);
} }
} }

View File

@ -4,16 +4,16 @@ package com.baomidou.samples.seata.common;
* 订单状态 * 订单状态
*/ */
public enum OrderStatus { public enum OrderStatus {
/** /**
* INIT * INIT
*/ */
INIT, INIT,
/** /**
* SUCCESS * SUCCESS
*/ */
SUCCESS, SUCCESS,
/** /**
* FAIL * FAIL
*/ */
FAIL FAIL
} }

View File

@ -15,12 +15,12 @@ import org.springframework.web.bind.annotation.RestController;
@Slf4j @Slf4j
public class OrderController { public class OrderController {
@Autowired @Autowired
private OrderService orderService; private OrderService orderService;
@PostMapping("/placeOrder") @PostMapping("/placeOrder")
public String placeOrder(@Validated @RequestBody PlaceOrderRequest request) { public String placeOrder(@Validated @RequestBody PlaceOrderRequest request) {
orderService.placeOrder(request); orderService.placeOrder(request);
return "下单成功"; return "下单成功";
} }
} }

View File

@ -1,23 +1,24 @@
package com.baomidou.samples.seata.dto; package com.baomidou.samples.seata.dto;
import javax.validation.constraints.NotNull;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import javax.validation.constraints.NotNull;
@Data @Data
@Builder @Builder
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor
public class PlaceOrderRequest { public class PlaceOrderRequest {
@NotNull @NotNull
private Long userId; private Long userId;
@NotNull @NotNull
private Long productId; private Long productId;
@NotNull @NotNull
private Integer amount; private Integer amount;
} }

View File

@ -11,7 +11,7 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor @NoArgsConstructor
public class ReduceBalanceRequest { public class ReduceBalanceRequest {
private Long userId; private Long userId;
private Integer price; private Integer price;
} }

View File

@ -11,7 +11,7 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor @NoArgsConstructor
public class ReduceStockRequest { public class ReduceStockRequest {
private Long productId; private Long productId;
private Integer amount; private Integer amount;
} }

View File

@ -2,21 +2,22 @@ package com.baomidou.samples.seata.entity;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import java.util.Date;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import java.util.Date;
@Data @Data
@Builder @Builder
public class Account { public class Account {
@TableId(type = IdType.AUTO) @TableId(type = IdType.AUTO)
private Long id; private Long id;
/** /**
* 余额 * 余额
*/ */
private Double balance; private Double balance;
private Date lastUpdateTime; private Date lastUpdateTime;
} }

View File

@ -12,27 +12,27 @@ import lombok.Data;
@TableName("p_order") @TableName("p_order")
public class Order { public class Order {
@TableId(type = IdType.AUTO) @TableId(type = IdType.AUTO)
private Integer id; private Integer id;
/** /**
* 用户ID * 用户ID
*/ */
private Long userId; private Long userId;
/** /**
* 商品ID * 商品ID
*/ */
private Long productId; private Long productId;
/** /**
* 订单状态 * 订单状态
*/ */
private OrderStatus status; private OrderStatus status;
/** /**
* 数量 * 数量
*/ */
private Integer amount; private Integer amount;
/** /**
* 总金额 * 总金额
*/ */
private Double totalPrice; private Double totalPrice;
} }

View File

@ -2,24 +2,25 @@ package com.baomidou.samples.seata.entity;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import java.util.Date;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import java.util.Date;
@Data @Data
@Builder @Builder
public class Product { public class Product {
@TableId(type = IdType.AUTO) @TableId(type = IdType.AUTO)
private Integer id; private Integer id;
/** /**
* 价格 * 价格
*/ */
private Double price; private Double price;
/** /**
* 库存 * 库存
*/ */
private Integer stock; private Integer stock;
private Date lastUpdateTime; private Date lastUpdateTime;
} }

View File

@ -2,10 +2,10 @@ package com.baomidou.samples.seata.service;
public interface AccountService { public interface AccountService {
/** /**
* @param userId 用户 ID * @param userId 用户 ID
* @param price 扣减金额 * @param price 扣减金额
*/ */
void reduceBalance(Long userId, Double price); void reduceBalance(Long userId, Double price);
} }

View File

@ -4,10 +4,10 @@ import com.baomidou.samples.seata.dto.PlaceOrderRequest;
public interface OrderService { public interface OrderService {
/** /**
* 下单 * 下单
* *
* @param placeOrderRequest 订单请求参数 * @param placeOrderRequest 订单请求参数
*/ */
void placeOrder(PlaceOrderRequest placeOrderRequest); void placeOrder(PlaceOrderRequest placeOrderRequest);
} }

View File

@ -2,12 +2,12 @@ package com.baomidou.samples.seata.service;
public interface ProductService { public interface ProductService {
/** /**
* 扣减库存 * 扣减库存
* *
* @param productId 商品 ID * @param productId 商品 ID
* @param amount 扣减数量 * @param amount 扣减数量
* @return 商品总价 * @return 商品总价
*/ */
Double reduceStock(Long productId, Integer amount); Double reduceStock(Long productId, Integer amount);
} }

View File

@ -5,43 +5,44 @@ import com.baomidou.samples.seata.dao.AccountDao;
import com.baomidou.samples.seata.entity.Account; import com.baomidou.samples.seata.entity.Account;
import com.baomidou.samples.seata.service.AccountService; import com.baomidou.samples.seata.service.AccountService;
import io.seata.core.context.RootContext; import io.seata.core.context.RootContext;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
@Slf4j @Slf4j
@Service @Service
public class AccountServiceImpl implements AccountService { public class AccountServiceImpl implements AccountService {
@Resource @Resource
private AccountDao accountDao; private AccountDao accountDao;
/** /**
* 事务传播特性设置为 REQUIRES_NEW 开启新的事务 * 事务传播特性设置为 REQUIRES_NEW 开启新的事务
*/ */
@DS("account") @DS("account")
@Override @Override
@Transactional(propagation = Propagation.REQUIRES_NEW) @Transactional(propagation = Propagation.REQUIRES_NEW)
public void reduceBalance(Long userId, Double price) { public void reduceBalance(Long userId, Double price) {
log.info("=============ACCOUNT START================="); log.info("=============ACCOUNT START=================");
log.info("当前 XID: {}", RootContext.getXID()); log.info("当前 XID: {}", RootContext.getXID());
Account account = accountDao.selectById(userId); Account account = accountDao.selectById(userId);
Double balance = account.getBalance(); Double balance = account.getBalance();
log.info("下单用户{}余额为 {},商品总价为{}", userId, balance, price); log.info("下单用户{}余额为 {},商品总价为{}", userId, balance, price);
if (balance < price) { if (balance < price) {
log.warn("用户 {} 余额不足,当前余额:{}", userId, balance); log.warn("用户 {} 余额不足,当前余额:{}", userId, balance);
throw new RuntimeException("余额不足"); throw new RuntimeException("余额不足");
}
log.info("开始扣减用户 {} 余额", userId);
double currentBalance = account.getBalance() - price;
account.setBalance(currentBalance);
accountDao.updateById(account);
log.info("扣减用户 {} 余额成功,扣减后用户账户余额为{}", userId, currentBalance);
log.info("=============ACCOUNT END=================");
} }
log.info("开始扣减用户 {} 余额", userId);
double currentBalance = account.getBalance() - price;
account.setBalance(currentBalance);
accountDao.updateById(account);
log.info("扣减用户 {} 余额成功,扣减后用户账户余额为{}", userId, currentBalance);
log.info("=============ACCOUNT END=================");
}
} }

View File

@ -10,54 +10,55 @@ import com.baomidou.samples.seata.service.OrderService;
import com.baomidou.samples.seata.service.ProductService; import com.baomidou.samples.seata.service.ProductService;
import io.seata.core.context.RootContext; import io.seata.core.context.RootContext;
import io.seata.spring.annotation.GlobalTransactional; import io.seata.spring.annotation.GlobalTransactional;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
@Slf4j @Slf4j
@Service @Service
public class OrderServiceImpl implements OrderService { public class OrderServiceImpl implements OrderService {
@Resource @Resource
private OrderDao orderDao; private OrderDao orderDao;
@Autowired @Autowired
private AccountService accountService; private AccountService accountService;
@Autowired @Autowired
private ProductService productService; private ProductService productService;
@DS("order") @DS("order")
@Override @Override
@Transactional @Transactional
@GlobalTransactional @GlobalTransactional
public void placeOrder(PlaceOrderRequest request) { public void placeOrder(PlaceOrderRequest request) {
log.info("=============ORDER START================="); log.info("=============ORDER START=================");
Long userId = request.getUserId(); Long userId = request.getUserId();
Long productId = request.getProductId(); Long productId = request.getProductId();
Integer amount = request.getAmount(); Integer amount = request.getAmount();
log.info("收到下单请求,用户:{}, 商品:{},数量:{}", userId, productId, amount); log.info("收到下单请求,用户:{}, 商品:{},数量:{}", userId, productId, amount);
log.info("当前 XID: {}", RootContext.getXID()); log.info("当前 XID: {}", RootContext.getXID());
Order order = Order.builder() Order order = Order.builder()
.userId(userId) .userId(userId)
.productId(productId) .productId(productId)
.status(OrderStatus.INIT) .status(OrderStatus.INIT)
.amount(amount) .amount(amount)
.build(); .build();
orderDao.insert(order); orderDao.insert(order);
log.info("订单一阶段生成,等待扣库存付款中"); log.info("订单一阶段生成,等待扣库存付款中");
// 扣减库存并计算总价 // 扣减库存并计算总价
Double totalPrice = productService.reduceStock(productId, amount); Double totalPrice = productService.reduceStock(productId, amount);
// 扣减余额 // 扣减余额
accountService.reduceBalance(userId, totalPrice); accountService.reduceBalance(userId, totalPrice);
order.setStatus(OrderStatus.SUCCESS); order.setStatus(OrderStatus.SUCCESS);
order.setTotalPrice(totalPrice); order.setTotalPrice(totalPrice);
orderDao.updateById(order); orderDao.updateById(order);
log.info("订单已成功下单"); log.info("订单已成功下单");
log.info("=============ORDER END================="); log.info("=============ORDER END=================");
} }
} }

View File

@ -5,46 +5,47 @@ import com.baomidou.samples.seata.dao.ProductDao;
import com.baomidou.samples.seata.entity.Product; import com.baomidou.samples.seata.entity.Product;
import com.baomidou.samples.seata.service.ProductService; import com.baomidou.samples.seata.service.ProductService;
import io.seata.core.context.RootContext; import io.seata.core.context.RootContext;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
@Slf4j @Slf4j
@Service @Service
public class ProductServiceImpl implements ProductService { public class ProductServiceImpl implements ProductService {
@Resource @Resource
private ProductDao productDao; private ProductDao productDao;
/** /**
* 事务传播特性设置为 REQUIRES_NEW 开启新的事务 * 事务传播特性设置为 REQUIRES_NEW 开启新的事务
*/ */
@DS("product") @DS("product")
@Transactional(propagation = Propagation.REQUIRES_NEW) @Transactional(propagation = Propagation.REQUIRES_NEW)
@Override @Override
public Double reduceStock(Long productId, Integer amount) { public Double reduceStock(Long productId, Integer amount) {
log.info("=============PRODUCT START================="); log.info("=============PRODUCT START=================");
log.info("当前 XID: {}", RootContext.getXID()); log.info("当前 XID: {}", RootContext.getXID());
// 检查库存 // 检查库存
Product product = productDao.selectById(productId); Product product = productDao.selectById(productId);
Integer stock = product.getStock(); Integer stock = product.getStock();
log.info("商品编号为 {} 的库存为{},订单商品数量为{}", productId, stock, amount); log.info("商品编号为 {} 的库存为{},订单商品数量为{}", productId, stock, amount);
if (stock < amount) { if (stock < amount) {
log.warn("商品编号为{} 库存不足,当前库存:{}", productId, stock); log.warn("商品编号为{} 库存不足,当前库存:{}", productId, stock);
throw new RuntimeException("库存不足"); throw new RuntimeException("库存不足");
}
log.info("开始扣减商品编号为 {} 库存,单价商品价格为{}", productId, product.getPrice());
// 扣减库存
int currentStock = stock - amount;
product.setStock(currentStock);
productDao.updateById(product);
double totalPrice = product.getPrice() * amount;
log.info("扣减商品编号为 {} 库存成功,扣减后库存为{}, {} 件商品总价为 {} ", productId, currentStock, amount, totalPrice);
log.info("=============PRODUCT END=================");
return totalPrice;
} }
log.info("开始扣减商品编号为 {} 库存,单价商品价格为{}", productId, product.getPrice());
// 扣减库存
int currentStock = stock - amount;
product.setStock(currentStock);
productDao.updateById(product);
double totalPrice = product.getPrice() * amount;
log.info("扣减商品编号为 {} 库存成功,扣减后库存为{}, {} 件商品总价为 {} ", productId, currentStock, amount, totalPrice);
log.info("=============PRODUCT END=================");
return totalPrice;
}
} }

View File

@ -8,8 +8,8 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
@MapperScan("com.baomidou.samples.spel.mapper") @MapperScan("com.baomidou.samples.spel.mapper")
public class Application { public class Application {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(Application.class, args); SpringApplication.run(Application.class, args);
} }
} }

View File

@ -2,28 +2,29 @@ package com.baomidou.samples.spel.controller;
import com.baomidou.samples.spel.entity.User; import com.baomidou.samples.spel.entity.User;
import com.baomidou.samples.spel.service.UserService; import com.baomidou.samples.spel.service.UserService;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
@RestController @RestController
public class UserController { public class UserController {
@Autowired @Autowired
private UserService userService; private UserService userService;
@GetMapping("/users") @GetMapping("/users")
public List<User> usersFromSession(HttpServletRequest request) { public List<User> usersFromSession(HttpServletRequest request) {
request.getSession().setAttribute("tenantName", "tenant1"); request.getSession().setAttribute("tenantName", "tenant1");
return userService.selectSpelBySession(); return userService.selectSpelBySession();
} }
@GetMapping("/users/header") @GetMapping("/users/header")
public String usersFromHeader() { public String usersFromHeader() {
userService.selectSpelByHeader(); userService.selectSpelByHeader();
return "success"; return "success";
} }
} }

View File

@ -2,43 +2,43 @@ package com.baomidou.samples.spel.entity;
public class User { public class User {
private Integer id; private Integer id;
private String name; private String name;
private Integer age; private Integer age;
private String tenantName; private String tenantName;
public Integer getId() { public Integer getId() {
return id; return id;
} }
public void setId(Integer id) { public void setId(Integer id) {
this.id = id; this.id = id;
} }
public String getName() { public String getName() {
return name; return name;
} }
public void setName(String name) { public void setName(String name) {
this.name = name; this.name = name;
} }
public Integer getAge() { public Integer getAge() {
return age; return age;
} }
public void setAge(Integer age) { public void setAge(Integer age) {
this.age = age; this.age = age;
} }
public String getTenantName() { public String getTenantName() {
return tenantName; return tenantName;
} }
public void setTenantName(String tenantName) { public void setTenantName(String tenantName) {
this.tenantName = tenantName; this.tenantName = tenantName;
} }
} }

View File

@ -1,17 +1,18 @@
package com.baomidou.samples.spel.mapper; package com.baomidou.samples.spel.mapper;
import com.baomidou.samples.spel.entity.User; import com.baomidou.samples.spel.entity.User;
import java.util.List;
import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Select;
import java.util.List;
//@DS("slave")这里可以使用但不建议不要和service同时使用 //@DS("slave")这里可以使用但不建议不要和service同时使用
public interface UserMapper { public interface UserMapper {
@Insert("INSERT INTO user (name,age) values (#{name},#{age})") @Insert("INSERT INTO user (name,age) values (#{name},#{age})")
boolean addUser(@Param("name") String name, @Param("age") Integer age); boolean addUser(@Param("name") String name, @Param("age") Integer age);
@Select("SELECT * FROM user") @Select("SELECT * FROM user")
List<User> selectUsers(); List<User> selectUsers();
} }

View File

@ -2,15 +2,16 @@ package com.baomidou.samples.spel.service;
import com.baomidou.samples.spel.entity.User; import com.baomidou.samples.spel.entity.User;
import java.util.List; import java.util.List;
public interface UserService { public interface UserService {
List selectSpelBySession(); List selectSpelBySession();
List selectSpelByHeader(); List selectSpelByHeader();
List selectSpelByKey(String tenantName); List selectSpelByKey(String tenantName);
List selecSpelByTenant(User user); List selecSpelByTenant(User user);
} }

View File

@ -5,38 +5,39 @@ import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.samples.spel.entity.User; import com.baomidou.samples.spel.entity.User;
import com.baomidou.samples.spel.mapper.UserMapper; import com.baomidou.samples.spel.mapper.UserMapper;
import com.baomidou.samples.spel.service.UserService; import com.baomidou.samples.spel.service.UserService;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service @Service
@DS("slave") @DS("slave")
public class UserServiceImpl implements UserService { public class UserServiceImpl implements UserService {
@Resource @Resource
private UserMapper userMapper; private UserMapper userMapper;
@Override @Override
@DS("#session.tenantName") @DS("#session.tenantName")
public List selectSpelBySession() { public List selectSpelBySession() {
return userMapper.selectUsers(); return userMapper.selectUsers();
} }
@Override @Override
@DS("#header.tenantName") @DS("#header.tenantName")
public List selectSpelByHeader() { public List selectSpelByHeader() {
return userMapper.selectUsers(); return userMapper.selectUsers();
} }
@Override @Override
@DS("#tenantName") @DS("#tenantName")
public List selectSpelByKey(String tenantName) { public List selectSpelByKey(String tenantName) {
return userMapper.selectUsers(); return userMapper.selectUsers();
} }
@Override @Override
@DS("#user.tenantName") @DS("#user.tenantName")
public List selecSpelByTenant(User user) { public List selecSpelByTenant(User user) {
return userMapper.selectUsers(); return userMapper.selectUsers();
} }
} }

View File

@ -1,12 +1,8 @@
package com.baomidou.samples.spel.test; package com.baomidou.samples.spel.test;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import com.baomidou.samples.spel.Application; import com.baomidou.samples.spel.Application;
import com.baomidou.samples.spel.entity.User; import com.baomidou.samples.spel.entity.User;
import com.baomidou.samples.spel.service.UserService; import com.baomidou.samples.spel.service.UserService;
import javax.servlet.http.HttpSession;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -19,51 +15,56 @@ import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.WebApplicationContext;
import javax.servlet.http.HttpSession;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class) @SpringBootTest(classes = Application.class)
public class ApplicationTest { public class ApplicationTest {
@Autowired @Autowired
private WebApplicationContext wac; private WebApplicationContext wac;
private MockMvc mockMvc; private MockMvc mockMvc;
@Autowired @Autowired
private UserService userService; private UserService userService;
@Autowired @Autowired
private HttpSession session; private HttpSession session;
@Before @Before
public void setup() { public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
} }
@Test @Test
public void selectSpelBySession() { public void selectSpelBySession() {
session.setAttribute("tenantName", "tenant1"); session.setAttribute("tenantName", "tenant1");
userService.selectSpelBySession(); userService.selectSpelBySession();
} }
@Test @Test
public void selectSpelByHeader() throws Exception { public void selectSpelByHeader() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/users/header") mockMvc.perform(MockMvcRequestBuilders.get("/users/header")
.contentType(MediaType.APPLICATION_FORM_URLENCODED) .contentType(MediaType.APPLICATION_FORM_URLENCODED)
.header("tenantName", "tenant1") .header("tenantName", "tenant1")
) )
.andDo(print()).andExpect(status().isOk()) .andDo(print()).andExpect(status().isOk())
.andReturn().getResponse() .andReturn().getResponse()
.getContentAsString(); .getContentAsString();
} }
@Test @Test
public void selectSpelByKey() { public void selectSpelByKey() {
userService.selectSpelByKey("tenant1"); userService.selectSpelByKey("tenant1");
} }
@Test @Test
public void selecSpelByTenant() { public void selecSpelByTenant() {
User user = new User(); User user = new User();
user.setTenantName("tenant2"); user.setTenantName("tenant2");
userService.selecSpelByTenant(user); userService.selecSpelByTenant(user);
} }
} }

View File

@ -3,65 +3,66 @@ package com.baomidou.samples.load;
import com.baomidou.dynamic.datasource.provider.AbstractJdbcDataSourceProvider; import com.baomidou.dynamic.datasource.provider.AbstractJdbcDataSourceProvider;
import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider; import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty; import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication @SpringBootApplication
public class Application { public class Application {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(Application.class, args); SpringApplication.run(Application.class, args);
} }
@Bean @Bean
public DynamicDataSourceProvider dynamicDataSourceProvider() { public DynamicDataSourceProvider dynamicDataSourceProvider() {
return new AbstractJdbcDataSourceProvider("org.h2.Driver", "jdbc:h2:mem:test", "sa", "") { return new AbstractJdbcDataSourceProvider("org.h2.Driver", "jdbc:h2:mem:test", "sa", "") {
@Override @Override
protected Map<String, DataSourceProperty> executeStmt(Statement statement) protected Map<String, DataSourceProperty> executeStmt(Statement statement)
throws SQLException { throws SQLException {
//*************** 实际运行应直接从库中查出演示所以需要先插入数据*************** //*************** 实际运行应直接从库中查出演示所以需要先插入数据***************
statement.execute("CREATE TABLE IF NOT EXISTS `DB`\n" statement.execute("CREATE TABLE IF NOT EXISTS `DB`\n"
+ "(\n" + "(\n"
+ " `name` VARCHAR(30) NULL DEFAULT NULL,\n" + " `name` VARCHAR(30) NULL DEFAULT NULL,\n"
+ " `username` VARCHAR(30) NULL DEFAULT NULL,\n" + " `username` VARCHAR(30) NULL DEFAULT NULL,\n"
+ " `password` VARCHAR(30) NULL DEFAULT NULL,\n" + " `password` VARCHAR(30) NULL DEFAULT NULL,\n"
+ " `url` VARCHAR(30) NULL DEFAULT NULL,\n" + " `url` VARCHAR(30) NULL DEFAULT NULL,\n"
+ " `driver` VARCHAR(30) NULL DEFAULT NULL\n" + " `driver` VARCHAR(30) NULL DEFAULT NULL\n"
+ ")"); + ")");
statement.executeUpdate( statement.executeUpdate(
"insert into DB values ('master','sa','','jdbc:h2:mem:test','org.h2.Driver')"); "insert into DB values ('master','sa','','jdbc:h2:mem:test','org.h2.Driver')");
statement.executeUpdate( statement.executeUpdate(
"insert into DB values ('slave_1','sa','','jdbc:h2:mem:test','org.h2.Driver')"); "insert into DB values ('slave_1','sa','','jdbc:h2:mem:test','org.h2.Driver')");
statement.executeUpdate( statement.executeUpdate(
"insert into DB values ('slave_2','sa','','jdbc:h2:mem:test','org.h2.Driver')"); "insert into DB values ('slave_2','sa','','jdbc:h2:mem:test','org.h2.Driver')");
statement.executeUpdate( statement.executeUpdate(
"insert into DB values ('slave_3','sa','','jdbc:h2:mem:test','org.h2.Driver')"); "insert into DB values ('slave_3','sa','','jdbc:h2:mem:test','org.h2.Driver')");
Map<String, DataSourceProperty> map = new HashMap<>(); Map<String, DataSourceProperty> map = new HashMap<>();
//*************** END *************** //*************** END ***************
ResultSet rs = statement.executeQuery("select * from DB"); ResultSet rs = statement.executeQuery("select * from DB");
while (rs.next()) { while (rs.next()) {
String name = rs.getString("name"); String name = rs.getString("name");
String username = rs.getString("username"); String username = rs.getString("username");
String password = rs.getString("password"); String password = rs.getString("password");
String url = rs.getString("url"); String url = rs.getString("url");
String driver = rs.getString("driver"); String driver = rs.getString("driver");
DataSourceProperty property = new DataSourceProperty(); DataSourceProperty property = new DataSourceProperty();
property.setUsername(username); property.setUsername(username);
property.setPassword(password); property.setPassword(password);
property.setUrl(url); property.setUrl(url);
property.setDriverClassName(driver); property.setDriverClassName(driver);
map.put(name, property); map.put(name, property);
} }
return map; return map;
} }
}; };
} }
} }

View File

@ -16,10 +16,11 @@
*/ */
package com.baomidou.dynamic.datasource; package com.baomidou.dynamic.datasource;
import org.springframework.jdbc.datasource.AbstractDataSource;
import javax.sql.DataSource;
import java.sql.Connection; import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
import javax.sql.DataSource;
import org.springframework.jdbc.datasource.AbstractDataSource;
/** /**
* 抽象动态获取数据源 * 抽象动态获取数据源
@ -29,34 +30,34 @@ import org.springframework.jdbc.datasource.AbstractDataSource;
*/ */
public abstract class AbstractRoutingDataSource extends AbstractDataSource { public abstract class AbstractRoutingDataSource extends AbstractDataSource {
/** /**
* 子类实现决定最终数据源 * 子类实现决定最终数据源
* *
* @return 数据源 * @return 数据源
*/ */
protected abstract DataSource determineDataSource(); protected abstract DataSource determineDataSource();
@Override @Override
public Connection getConnection() throws SQLException { public Connection getConnection() throws SQLException {
return determineDataSource().getConnection(); return determineDataSource().getConnection();
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return determineDataSource().getConnection(username, password);
}
@Override
@SuppressWarnings("unchecked")
public <T> T unwrap(Class<T> iface) throws SQLException {
if (iface.isInstance(this)) {
return (T) this;
} }
return determineDataSource().unwrap(iface);
}
@Override @Override
public boolean isWrapperFor(Class<?> iface) throws SQLException { public Connection getConnection(String username, String password) throws SQLException {
return (iface.isInstance(this) || determineDataSource().isWrapperFor(iface)); return determineDataSource().getConnection(username, password);
} }
@Override
@SuppressWarnings("unchecked")
public <T> T unwrap(Class<T> iface) throws SQLException {
if (iface.isInstance(this)) {
return (T) this;
}
return determineDataSource().unwrap(iface);
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return (iface.isInstance(this) || determineDataSource().isWrapperFor(iface));
}
} }

View File

@ -19,9 +19,10 @@ package com.baomidou.dynamic.datasource;
import com.baomidou.dynamic.datasource.matcher.ExpressionMatcher; import com.baomidou.dynamic.datasource.matcher.ExpressionMatcher;
import com.baomidou.dynamic.datasource.matcher.Matcher; import com.baomidou.dynamic.datasource.matcher.Matcher;
import com.baomidou.dynamic.datasource.matcher.RegexMatcher; import com.baomidou.dynamic.datasource.matcher.RegexMatcher;
import lombok.Getter;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import lombok.Getter;
/** /**
* 基于多种策略的自动切换数据源 * 基于多种策略的自动切换数据源
@ -31,24 +32,24 @@ import lombok.Getter;
*/ */
public class DynamicDataSourceConfigure { public class DynamicDataSourceConfigure {
@Getter @Getter
private List<Matcher> matchers = new LinkedList<>(); private List<Matcher> matchers = new LinkedList<>();
private DynamicDataSourceConfigure() { private DynamicDataSourceConfigure() {
} }
public static DynamicDataSourceConfigure config() { public static DynamicDataSourceConfigure config() {
return new DynamicDataSourceConfigure(); return new DynamicDataSourceConfigure();
} }
public DynamicDataSourceConfigure regexMatchers(String pattern, String ds) { public DynamicDataSourceConfigure regexMatchers(String pattern, String ds) {
matchers.add(new RegexMatcher(pattern, ds)); matchers.add(new RegexMatcher(pattern, ds));
return this; return this;
} }
public DynamicDataSourceConfigure expressionMatchers(String expression, String ds) { public DynamicDataSourceConfigure expressionMatchers(String expression, String ds) {
matchers.add(new ExpressionMatcher(expression, ds)); matchers.add(new ExpressionMatcher(expression, ds));
return this; return this;
} }
} }

View File

@ -17,10 +17,11 @@
package com.baomidou.dynamic.datasource; package com.baomidou.dynamic.datasource;
import com.baomidou.dynamic.datasource.strategy.DynamicDataSourceStrategy; import com.baomidou.dynamic.datasource.strategy.DynamicDataSourceStrategy;
import lombok.Data;
import javax.sql.DataSource;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import javax.sql.DataSource;
import lombok.Data;
/** /**
* 分组数据源 * 分组数据源
@ -31,30 +32,30 @@ import lombok.Data;
@Data @Data
public class DynamicGroupDataSource { public class DynamicGroupDataSource {
private String groupName; private String groupName;
private DynamicDataSourceStrategy dynamicDataSourceStrategy; private DynamicDataSourceStrategy dynamicDataSourceStrategy;
private List<DataSource> dataSources = new LinkedList<>(); private List<DataSource> dataSources = new LinkedList<>();
public DynamicGroupDataSource(String groupName, DynamicDataSourceStrategy dynamicDataSourceStrategy) { public DynamicGroupDataSource(String groupName, DynamicDataSourceStrategy dynamicDataSourceStrategy) {
this.groupName = groupName; this.groupName = groupName;
this.dynamicDataSourceStrategy = dynamicDataSourceStrategy; this.dynamicDataSourceStrategy = dynamicDataSourceStrategy;
} }
public void addDatasource(DataSource dataSource) { public void addDatasource(DataSource dataSource) {
dataSources.add(dataSource); dataSources.add(dataSource);
} }
public void removeDatasource(DataSource dataSource) { public void removeDatasource(DataSource dataSource) {
dataSources.remove(dataSource); dataSources.remove(dataSource);
} }
public DataSource determineDataSource() { public DataSource determineDataSource() {
return dynamicDataSourceStrategy.determineDataSource(dataSources); return dynamicDataSourceStrategy.determineDataSource(dataSources);
} }
public int size() { public int size() {
return dataSources.size(); return dataSources.size();
} }
} }

View File

@ -21,18 +21,19 @@ import com.baomidou.dynamic.datasource.strategy.DynamicDataSourceStrategy;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder; import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.p6spy.engine.spy.P6DataSource; import com.p6spy.engine.spy.P6DataSource;
import io.seata.rm.datasource.DataSourceProxy; import io.seata.rm.datasource.DataSourceProxy;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.StringUtils;
import javax.sql.DataSource;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import javax.sql.DataSource;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.StringUtils;
/** /**
* 核心动态数据源组件 * 核心动态数据源组件
@ -43,227 +44,227 @@ import org.springframework.util.StringUtils;
@Slf4j @Slf4j
public class DynamicRoutingDataSource extends AbstractRoutingDataSource implements InitializingBean, DisposableBean { public class DynamicRoutingDataSource extends AbstractRoutingDataSource implements InitializingBean, DisposableBean {
private static final String UNDERLINE = "_"; private static final String UNDERLINE = "_";
@Setter @Setter
private DynamicDataSourceProvider provider; private DynamicDataSourceProvider provider;
@Setter @Setter
private String primary; private String primary;
@Setter @Setter
private boolean strict; private boolean strict;
@Setter @Setter
private Class<? extends DynamicDataSourceStrategy> strategy; private Class<? extends DynamicDataSourceStrategy> strategy;
private boolean p6spy; private boolean p6spy;
private boolean seata; private boolean seata;
/** /**
* 所有数据库 * 所有数据库
*/ */
private Map<String, DataSource> dataSourceMap = new LinkedHashMap<>(); private Map<String, DataSource> dataSourceMap = new LinkedHashMap<>();
/** /**
* 分组数据库 * 分组数据库
*/ */
private Map<String, DynamicGroupDataSource> groupDataSources = new ConcurrentHashMap<>(); private Map<String, DynamicGroupDataSource> groupDataSources = new ConcurrentHashMap<>();
@Override @Override
public DataSource determineDataSource() { public DataSource determineDataSource() {
return getDataSource(DynamicDataSourceContextHolder.peek()); return getDataSource(DynamicDataSourceContextHolder.peek());
}
private DataSource determinePrimaryDataSource() {
log.debug("dynamic-datasource switch to the primary datasource");
return groupDataSources.containsKey(primary) ? groupDataSources.get(primary).determineDataSource() : dataSourceMap.get(primary);
}
/**
* 获取当前所有的数据源
*
* @return 当前所有数据源
*/
public Map<String, DataSource> getCurrentDataSources() {
return dataSourceMap;
}
/**
* 获取的当前所有的分组数据源
*
* @return 当前所有的分组数据源
*/
public Map<String, DynamicGroupDataSource> getCurrentGroupDataSources() {
return groupDataSources;
}
/**
* 获取数据源
*
* @param ds 数据源名称
* @return 数据源
*/
public DataSource getDataSource(String ds) {
if (StringUtils.isEmpty(ds)) {
return determinePrimaryDataSource();
} else if (!groupDataSources.isEmpty() && groupDataSources.containsKey(ds)) {
log.debug("dynamic-datasource switch to the datasource named [{}]", ds);
return groupDataSources.get(ds).determineDataSource();
} else if (dataSourceMap.containsKey(ds)) {
log.debug("dynamic-datasource switch to the datasource named [{}]", ds);
return dataSourceMap.get(ds);
} }
if (strict) {
throw new RuntimeException("dynamic-datasource could not find a datasource named" + ds);
}
return determinePrimaryDataSource();
}
/** private DataSource determinePrimaryDataSource() {
* 添加数据源 log.debug("dynamic-datasource switch to the primary datasource");
* return groupDataSources.containsKey(primary) ? groupDataSources.get(primary).determineDataSource() : dataSourceMap.get(primary);
* @param ds 数据源名称
* @param dataSource 数据源
*/
public synchronized void addDataSource(String ds, DataSource dataSource) {
if (!dataSourceMap.containsKey(ds)) {
dataSource = wrapDataSource(ds, dataSource);
dataSourceMap.put(ds, dataSource);
this.addGroupDataSource(ds, dataSource);
log.info("dynamic-datasource - load a datasource named [{}] success", ds);
} else {
log.warn("dynamic-datasource - load a datasource named [{}] failed, because it already exist", ds);
} }
}
private DataSource wrapDataSource(String ds, DataSource dataSource) { /**
if (p6spy) { * 获取当前所有的数据源
dataSource = new P6DataSource(dataSource); *
log.info("dynamic-datasource [{}] wrap p6spy plugin", ds); * @return 当前所有数据源
*/
public Map<String, DataSource> getCurrentDataSources() {
return dataSourceMap;
} }
if (seata) {
dataSource = new DataSourceProxy(dataSource);
log.info("dynamic-datasource [{}] wrap seata plugin", ds);
}
return dataSource;
}
private void addGroupDataSource(String ds, DataSource dataSource) { /**
if (ds.contains(UNDERLINE)) { * 获取的当前所有的分组数据源
String group = ds.split(UNDERLINE)[0]; *
if (groupDataSources.containsKey(group)) { * @return 当前所有的分组数据源
groupDataSources.get(group).addDatasource(dataSource); */
} else { public Map<String, DynamicGroupDataSource> getCurrentGroupDataSources() {
return groupDataSources;
}
/**
* 获取数据源
*
* @param ds 数据源名称
* @return 数据源
*/
public DataSource getDataSource(String ds) {
if (StringUtils.isEmpty(ds)) {
return determinePrimaryDataSource();
} else if (!groupDataSources.isEmpty() && groupDataSources.containsKey(ds)) {
log.debug("dynamic-datasource switch to the datasource named [{}]", ds);
return groupDataSources.get(ds).determineDataSource();
} else if (dataSourceMap.containsKey(ds)) {
log.debug("dynamic-datasource switch to the datasource named [{}]", ds);
return dataSourceMap.get(ds);
}
if (strict) {
throw new RuntimeException("dynamic-datasource could not find a datasource named" + ds);
}
return determinePrimaryDataSource();
}
/**
* 添加数据源
*
* @param ds 数据源名称
* @param dataSource 数据源
*/
public synchronized void addDataSource(String ds, DataSource dataSource) {
if (!dataSourceMap.containsKey(ds)) {
dataSource = wrapDataSource(ds, dataSource);
dataSourceMap.put(ds, dataSource);
this.addGroupDataSource(ds, dataSource);
log.info("dynamic-datasource - load a datasource named [{}] success", ds);
} else {
log.warn("dynamic-datasource - load a datasource named [{}] failed, because it already exist", ds);
}
}
private DataSource wrapDataSource(String ds, DataSource dataSource) {
if (p6spy) {
dataSource = new P6DataSource(dataSource);
log.info("dynamic-datasource [{}] wrap p6spy plugin", ds);
}
if (seata) {
dataSource = new DataSourceProxy(dataSource);
log.info("dynamic-datasource [{}] wrap seata plugin", ds);
}
return dataSource;
}
private void addGroupDataSource(String ds, DataSource dataSource) {
if (ds.contains(UNDERLINE)) {
String group = ds.split(UNDERLINE)[0];
if (groupDataSources.containsKey(group)) {
groupDataSources.get(group).addDatasource(dataSource);
} else {
try {
DynamicGroupDataSource groupDatasource = new DynamicGroupDataSource(group, strategy.newInstance());
groupDatasource.addDatasource(dataSource);
groupDataSources.put(group, groupDatasource);
} catch (Exception e) {
log.error("dynamic-datasource - add the datasource named [{}] error", ds, e);
dataSourceMap.remove(ds);
}
}
}
}
/**
* 删除数据源
*
* @param ds 数据源名称
*/
public synchronized void removeDataSource(String ds) {
if (!StringUtils.hasText(ds)) {
throw new RuntimeException("remove parameter could not be empty");
}
if (primary.equals(ds)) {
throw new RuntimeException("could not remove primary datasource");
}
if (dataSourceMap.containsKey(ds)) {
DataSource dataSource = dataSourceMap.get(ds);
try {
closeDataSource(ds, dataSource);
} catch (Exception e) {
throw new RuntimeException("dynamic-datasource - remove the database named " + ds + " failed", e);
}
dataSourceMap.remove(ds);
if (ds.contains(UNDERLINE)) {
String group = ds.split(UNDERLINE)[0];
if (groupDataSources.containsKey(group)) {
groupDataSources.get(group).removeDatasource(dataSource);
}
}
log.info("dynamic-datasource - remove the database named [{}] success", ds);
} else {
log.warn("dynamic-datasource - could not find a database named [{}]", ds);
}
}
public void setP6spy(boolean p6spy) {
if (p6spy) {
try {
Class.forName("com.p6spy.engine.spy.P6DataSource");
log.info("dynamic-datasource detect P6SPY plugin and enabled it");
this.p6spy = true;
} catch (Exception e) {
log.warn("dynamic-datasource enabled P6SPY ,however without p6spy dependency");
}
} else {
this.p6spy = false;
}
}
public void setSeata(boolean seata) {
if (seata) {
try {
Class.forName("io.seata.rm.datasource.DataSourceProxy");
this.seata = true;
log.info("dynamic-datasource detect ALIBABA SEATA and enabled it");
} catch (Exception e) {
this.seata = false;
log.warn("dynamic-datasource enabled ALIBABA SEATA ,however without seata dependency");
}
}
}
@Override
public void destroy() throws Exception {
log.info("dynamic-datasource start closing ....");
for (Map.Entry<String, DataSource> item : dataSourceMap.entrySet()) {
closeDataSource(item.getKey(), item.getValue());
}
log.info("dynamic-datasource all closed success,bye");
}
private void closeDataSource(String name, DataSource dataSource)
throws NoSuchFieldException, IllegalAccessException, InvocationTargetException {
if (seata) {
DataSourceProxy dataSourceProxy = (DataSourceProxy) dataSource;
dataSource = dataSourceProxy.getTargetDataSource();
}
if (p6spy) {
Field realDataSourceField = P6DataSource.class.getDeclaredField("realDataSource");
realDataSourceField.setAccessible(true);
dataSource = (DataSource) realDataSourceField.get(dataSource);
}
Class<? extends DataSource> clazz = dataSource.getClass();
try { try {
DynamicGroupDataSource groupDatasource = new DynamicGroupDataSource(group, strategy.newInstance()); Method closeMethod = clazz.getDeclaredMethod("close");
groupDatasource.addDatasource(dataSource); closeMethod.invoke(dataSource);
groupDataSources.put(group, groupDatasource); } catch (NoSuchMethodException e) {
} catch (Exception e) { log.warn("dynamic-datasource close the datasource named [{}] failed,", name);
log.error("dynamic-datasource - add the datasource named [{}] error", ds, e);
dataSourceMap.remove(ds);
} }
}
} }
}
/** @Override
* 删除数据源 public void afterPropertiesSet() throws Exception {
* Map<String, DataSource> dataSources = provider.loadDataSources();
* @param ds 数据源名称 // 添加并分组数据源
*/ for (Map.Entry<String, DataSource> dsItem : dataSources.entrySet()) {
public synchronized void removeDataSource(String ds) { addDataSource(dsItem.getKey(), dsItem.getValue());
if (!StringUtils.hasText(ds)) { }
throw new RuntimeException("remove parameter could not be empty"); // 检测默认数据源设置
} if (groupDataSources.containsKey(primary)) {
if (primary.equals(ds)) { log.info("dynamic-datasource initial loaded [{}] datasource,primary group datasource named [{}]", dataSources.size(), primary);
throw new RuntimeException("could not remove primary datasource"); } else if (dataSourceMap.containsKey(primary)) {
} log.info("dynamic-datasource initial loaded [{}] datasource,primary datasource named [{}]", dataSources.size(), primary);
if (dataSourceMap.containsKey(ds)) { } else {
DataSource dataSource = dataSourceMap.get(ds); throw new RuntimeException("dynamic-datasource Please check the setting of primary");
try {
closeDataSource(ds, dataSource);
} catch (Exception e) {
throw new RuntimeException("dynamic-datasource - remove the database named " + ds + " failed", e);
}
dataSourceMap.remove(ds);
if (ds.contains(UNDERLINE)) {
String group = ds.split(UNDERLINE)[0];
if (groupDataSources.containsKey(group)) {
groupDataSources.get(group).removeDatasource(dataSource);
} }
}
log.info("dynamic-datasource - remove the database named [{}] success", ds);
} else {
log.warn("dynamic-datasource - could not find a database named [{}]", ds);
} }
}
public void setP6spy(boolean p6spy) {
if (p6spy) {
try {
Class.forName("com.p6spy.engine.spy.P6DataSource");
log.info("dynamic-datasource detect P6SPY plugin and enabled it");
this.p6spy = true;
} catch (Exception e) {
log.warn("dynamic-datasource enabled P6SPY ,however without p6spy dependency");
}
} else {
this.p6spy = false;
}
}
public void setSeata(boolean seata) {
if (seata) {
try {
Class.forName("io.seata.rm.datasource.DataSourceProxy");
this.seata = true;
log.info("dynamic-datasource detect ALIBABA SEATA and enabled it");
} catch (Exception e) {
this.seata = false;
log.warn("dynamic-datasource enabled ALIBABA SEATA ,however without seata dependency");
}
}
}
@Override
public void destroy() throws Exception {
log.info("dynamic-datasource start closing ....");
for (Map.Entry<String, DataSource> item : dataSourceMap.entrySet()) {
closeDataSource(item.getKey(), item.getValue());
}
log.info("dynamic-datasource all closed success,bye");
}
private void closeDataSource(String name, DataSource dataSource)
throws NoSuchFieldException, IllegalAccessException, InvocationTargetException {
if (seata) {
DataSourceProxy dataSourceProxy = (DataSourceProxy) dataSource;
dataSource = dataSourceProxy.getTargetDataSource();
}
if (p6spy) {
Field realDataSourceField = P6DataSource.class.getDeclaredField("realDataSource");
realDataSourceField.setAccessible(true);
dataSource = (DataSource) realDataSourceField.get(dataSource);
}
Class<? extends DataSource> clazz = dataSource.getClass();
try {
Method closeMethod = clazz.getDeclaredMethod("close");
closeMethod.invoke(dataSource);
} catch (NoSuchMethodException e) {
log.warn("dynamic-datasource close the datasource named [{}] failed,", name);
}
}
@Override
public void afterPropertiesSet() throws Exception {
Map<String, DataSource> dataSources = provider.loadDataSources();
// 添加并分组数据源
for (Map.Entry<String, DataSource> dsItem : dataSources.entrySet()) {
addDataSource(dsItem.getKey(), dsItem.getValue());
}
// 检测默认数据源设置
if (groupDataSources.containsKey(primary)) {
log.info("dynamic-datasource initial loaded [{}] datasource,primary group datasource named [{}]", dataSources.size(), primary);
} else if (dataSourceMap.containsKey(primary)) {
log.info("dynamic-datasource initial loaded [{}] datasource,primary datasource named [{}]", dataSources.size(), primary);
} else {
throw new RuntimeException("dynamic-datasource Please check the setting of primary");
}
}
} }

View File

@ -17,11 +17,7 @@
package com.baomidou.dynamic.datasource.annotation; package com.baomidou.dynamic.datasource.annotation;
import java.lang.annotation.Documented; import java.lang.annotation.*;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** /**
* The core Annotation to switch datasource. It can be annotate at class or method. * The core Annotation to switch datasource. It can be annotate at class or method.
@ -34,10 +30,10 @@ import java.lang.annotation.Target;
@Documented @Documented
public @interface DS { public @interface DS {
/** /**
* groupName or specific database name or spring SPEL name. * groupName or specific database name or spring SPEL name.
* *
* @return the database you want to switch * @return the database you want to switch
*/ */
String value(); String value();
} }

View File

@ -16,9 +16,10 @@
*/ */
package com.baomidou.dynamic.datasource.aop; package com.baomidou.dynamic.datasource.aop;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Map; import java.util.Map;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
/** /**
* @author TaoYu * @author TaoYu
@ -26,22 +27,22 @@ import org.springframework.aop.aspectj.AspectJExpressionPointcut;
*/ */
public class DynamicAspectJExpressionPointcut extends AspectJExpressionPointcut { public class DynamicAspectJExpressionPointcut extends AspectJExpressionPointcut {
private Map<String, String> matchesCache; private Map<String, String> matchesCache;
private String ds; private String ds;
public DynamicAspectJExpressionPointcut(String expression, String ds, Map<String, String> matchesCache) { public DynamicAspectJExpressionPointcut(String expression, String ds, Map<String, String> matchesCache) {
this.ds = ds; this.ds = ds;
this.matchesCache = matchesCache; this.matchesCache = matchesCache;
setExpression(expression); setExpression(expression);
} }
@Override @Override
public boolean matches(Method method, Class<?> targetClass, boolean beanHasIntroductions) { public boolean matches(Method method, Class<?> targetClass, boolean beanHasIntroductions) {
boolean matches = super.matches(method, targetClass, beanHasIntroductions); boolean matches = super.matches(method, targetClass, beanHasIntroductions);
if (matches) { if (matches) {
matchesCache.put(targetClass.getName() + "." + method.getName(), ds); matchesCache.put(targetClass.getName() + "." + method.getName(), ds);
}
return matches;
} }
return matches;
}
} }

View File

@ -21,10 +21,6 @@ import com.baomidou.dynamic.datasource.matcher.Matcher;
import com.baomidou.dynamic.datasource.matcher.RegexMatcher; import com.baomidou.dynamic.datasource.matcher.RegexMatcher;
import com.baomidou.dynamic.datasource.processor.DsProcessor; import com.baomidou.dynamic.datasource.processor.DsProcessor;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder; import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.Setter; import lombok.Setter;
import org.aopalliance.aop.Advice; import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInterceptor;
@ -36,90 +32,95 @@ import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanFactoryAware;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/** /**
* @author TaoYu * @author TaoYu
* @since 1.2.0 * @since 1.2.0
*/ */
public class DynamicDataSourceAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware { public class DynamicDataSourceAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware {
/** /**
* The identification of SPEL * The identification of SPEL
*/ */
private static final String DYNAMIC_PREFIX = "#"; private static final String DYNAMIC_PREFIX = "#";
@Setter @Setter
private DsProcessor dsProcessor; private DsProcessor dsProcessor;
private Advice advice; private Advice advice;
private Pointcut pointcut; private Pointcut pointcut;
private Map<String, String> matchesCache = new HashMap<>(); private Map<String, String> matchesCache = new HashMap<>();
public DynamicDataSourceAdvisor(List<Matcher> matchers) { public DynamicDataSourceAdvisor(List<Matcher> matchers) {
this.pointcut = buildPointcut(matchers); this.pointcut = buildPointcut(matchers);
this.advice = buildAdvice(); this.advice = buildAdvice();
}
private Advice buildAdvice() {
return new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
try {
Method method = invocation.getMethod();
String methodPath = invocation.getThis().getClass().getName() + "." + method.getName();
String key = matchesCache.get(methodPath);
if (key != null && !key.isEmpty() && key.startsWith(DYNAMIC_PREFIX)) {
key = dsProcessor.determineDatasource(invocation, key);
}
DynamicDataSourceContextHolder.push(key);
return invocation.proceed();
} finally {
DynamicDataSourceContextHolder.poll();
}
}
};
}
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
@Override
public Advice getAdvice() {
return this.advice;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
if (this.advice instanceof BeanFactoryAware) {
((BeanFactoryAware) this.advice).setBeanFactory(beanFactory);
} }
}
private Pointcut buildPointcut(List<Matcher> matchers) { private Advice buildAdvice() {
ComposablePointcut composablePointcut = null; return new MethodInterceptor() {
for (Matcher matcher : matchers) { @Override
if (matcher instanceof RegexMatcher) { public Object invoke(MethodInvocation invocation) throws Throwable {
RegexMatcher regexMatcher = (RegexMatcher) matcher; try {
Pointcut pointcut = new DynamicJdkRegexpMethodPointcut(regexMatcher.getPattern(), regexMatcher.getDs(), matchesCache); Method method = invocation.getMethod();
if (composablePointcut == null) { String methodPath = invocation.getThis().getClass().getName() + "." + method.getName();
composablePointcut = new ComposablePointcut(pointcut); String key = matchesCache.get(methodPath);
} else { if (key != null && !key.isEmpty() && key.startsWith(DYNAMIC_PREFIX)) {
composablePointcut.union(pointcut); key = dsProcessor.determineDatasource(invocation, key);
} }
} else { DynamicDataSourceContextHolder.push(key);
ExpressionMatcher expressionMatcher = (ExpressionMatcher) matcher; return invocation.proceed();
Pointcut pointcut = new DynamicAspectJExpressionPointcut(expressionMatcher.getExpression(), expressionMatcher.getDs(), } finally {
matchesCache); DynamicDataSourceContextHolder.poll();
if (composablePointcut == null) { }
composablePointcut = new ComposablePointcut(pointcut); }
} else { };
composablePointcut.union(pointcut); }
}
} @Override
public Pointcut getPointcut() {
return this.pointcut;
}
@Override
public Advice getAdvice() {
return this.advice;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
if (this.advice instanceof BeanFactoryAware) {
((BeanFactoryAware) this.advice).setBeanFactory(beanFactory);
}
}
private Pointcut buildPointcut(List<Matcher> matchers) {
ComposablePointcut composablePointcut = null;
for (Matcher matcher : matchers) {
if (matcher instanceof RegexMatcher) {
RegexMatcher regexMatcher = (RegexMatcher) matcher;
Pointcut pointcut = new DynamicJdkRegexpMethodPointcut(regexMatcher.getPattern(), regexMatcher.getDs(), matchesCache);
if (composablePointcut == null) {
composablePointcut = new ComposablePointcut(pointcut);
} else {
composablePointcut.union(pointcut);
}
} else {
ExpressionMatcher expressionMatcher = (ExpressionMatcher) matcher;
Pointcut pointcut = new DynamicAspectJExpressionPointcut(expressionMatcher.getExpression(), expressionMatcher.getDs(),
matchesCache);
if (composablePointcut == null) {
composablePointcut = new ComposablePointcut(pointcut);
} else {
composablePointcut.union(pointcut);
}
}
}
return composablePointcut;
} }
return composablePointcut;
}
} }

View File

@ -32,37 +32,37 @@ import org.springframework.beans.factory.BeanFactoryAware;
* @since 1.2.0 * @since 1.2.0
*/ */
public class DynamicDataSourceAnnotationAdvisor extends AbstractPointcutAdvisor implements public class DynamicDataSourceAnnotationAdvisor extends AbstractPointcutAdvisor implements
BeanFactoryAware { BeanFactoryAware {
private Advice advice; private Advice advice;
private Pointcut pointcut; private Pointcut pointcut;
public DynamicDataSourceAnnotationAdvisor(@NonNull DynamicDataSourceAnnotationInterceptor dynamicDataSourceAnnotationInterceptor) { public DynamicDataSourceAnnotationAdvisor(@NonNull DynamicDataSourceAnnotationInterceptor dynamicDataSourceAnnotationInterceptor) {
this.advice = dynamicDataSourceAnnotationInterceptor; this.advice = dynamicDataSourceAnnotationInterceptor;
this.pointcut = buildPointcut(); this.pointcut = buildPointcut();
}
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
@Override
public Advice getAdvice() {
return this.advice;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
if (this.advice instanceof BeanFactoryAware) {
((BeanFactoryAware) this.advice).setBeanFactory(beanFactory);
} }
}
private Pointcut buildPointcut() { @Override
Pointcut cpc = new AnnotationMatchingPointcut(DS.class, true); public Pointcut getPointcut() {
Pointcut mpc = AnnotationMatchingPointcut.forMethodAnnotation(DS.class); return this.pointcut;
return new ComposablePointcut(cpc).union(mpc); }
}
@Override
public Advice getAdvice() {
return this.advice;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
if (this.advice instanceof BeanFactoryAware) {
((BeanFactoryAware) this.advice).setBeanFactory(beanFactory);
}
}
private Pointcut buildPointcut() {
Pointcut cpc = new AnnotationMatchingPointcut(DS.class, true);
Pointcut mpc = AnnotationMatchingPointcut.forMethodAnnotation(DS.class);
return new ComposablePointcut(cpc).union(mpc);
}
} }

View File

@ -20,12 +20,13 @@ import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.dynamic.datasource.processor.DsProcessor; import com.baomidou.dynamic.datasource.processor.DsProcessor;
import com.baomidou.dynamic.datasource.support.DataSourceClassResolver; import com.baomidou.dynamic.datasource.support.DataSourceClassResolver;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder; import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import java.lang.reflect.Method;
import lombok.Setter; import lombok.Setter;
import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation; import org.aopalliance.intercept.MethodInvocation;
import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.annotation.AnnotationUtils;
import java.lang.reflect.Method;
/** /**
* Core Interceptor of Dynamic Datasource * Core Interceptor of Dynamic Datasource
* *
@ -34,29 +35,29 @@ import org.springframework.core.annotation.AnnotationUtils;
*/ */
public class DynamicDataSourceAnnotationInterceptor implements MethodInterceptor { public class DynamicDataSourceAnnotationInterceptor implements MethodInterceptor {
/** /**
* The identification of SPEL. * The identification of SPEL.
*/ */
private static final String DYNAMIC_PREFIX = "#"; private static final String DYNAMIC_PREFIX = "#";
private static final DataSourceClassResolver RESOLVER = new DataSourceClassResolver(); private static final DataSourceClassResolver RESOLVER = new DataSourceClassResolver();
@Setter @Setter
private DsProcessor dsProcessor; private DsProcessor dsProcessor;
@Override @Override
public Object invoke(MethodInvocation invocation) throws Throwable { public Object invoke(MethodInvocation invocation) throws Throwable {
try { try {
DynamicDataSourceContextHolder.push(determineDatasource(invocation)); DynamicDataSourceContextHolder.push(determineDatasource(invocation));
return invocation.proceed(); return invocation.proceed();
} finally { } finally {
DynamicDataSourceContextHolder.poll(); DynamicDataSourceContextHolder.poll();
}
} }
}
private String determineDatasource(MethodInvocation invocation) throws Throwable { private String determineDatasource(MethodInvocation invocation) throws Throwable {
Method method = invocation.getMethod(); Method method = invocation.getMethod();
DS ds = method.isAnnotationPresent(DS.class) ? method.getAnnotation(DS.class) DS ds = method.isAnnotationPresent(DS.class) ? method.getAnnotation(DS.class)
: AnnotationUtils.findAnnotation(RESOLVER.targetClass(invocation), DS.class); : AnnotationUtils.findAnnotation(RESOLVER.targetClass(invocation), DS.class);
String key = ds.value(); String key = ds.value();
return (!key.isEmpty() && key.startsWith(DYNAMIC_PREFIX)) ? dsProcessor.determineDatasource(invocation, key) : key; return (!key.isEmpty() && key.startsWith(DYNAMIC_PREFIX)) ? dsProcessor.determineDatasource(invocation, key) : key;
} }
} }

View File

@ -16,31 +16,32 @@
*/ */
package com.baomidou.dynamic.datasource.aop; package com.baomidou.dynamic.datasource.aop;
import java.util.Map;
import org.springframework.aop.support.JdkRegexpMethodPointcut; import org.springframework.aop.support.JdkRegexpMethodPointcut;
import java.util.Map;
/** /**
* @author TaoYu * @author TaoYu
* @since 2.5.0 * @since 2.5.0
*/ */
public class DynamicJdkRegexpMethodPointcut extends JdkRegexpMethodPointcut { public class DynamicJdkRegexpMethodPointcut extends JdkRegexpMethodPointcut {
private Map<String, String> matchesCache; private Map<String, String> matchesCache;
private String ds; private String ds;
public DynamicJdkRegexpMethodPointcut(String pattern, String ds, Map<String, String> matchesCache) { public DynamicJdkRegexpMethodPointcut(String pattern, String ds, Map<String, String> matchesCache) {
this.ds = ds; this.ds = ds;
this.matchesCache = matchesCache; this.matchesCache = matchesCache;
setPattern(pattern); setPattern(pattern);
} }
@Override @Override
protected boolean matches(String pattern, int patternIndex) { protected boolean matches(String pattern, int patternIndex) {
boolean matches = super.matches(pattern, patternIndex); boolean matches = super.matches(pattern, patternIndex);
if (matches) { if (matches) {
matchesCache.put(pattern, ds); matchesCache.put(pattern, ds);
}
return matches;
} }
return matches;
}
} }

View File

@ -18,11 +18,12 @@ package com.baomidou.dynamic.datasource.creator;
import com.baomidou.dynamic.datasource.exception.ErrorCreateDataSourceException; import com.baomidou.dynamic.datasource.exception.ErrorCreateDataSourceException;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty; import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import java.lang.reflect.Method;
import javax.sql.DataSource;
import lombok.Data; import lombok.Data;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import javax.sql.DataSource;
import java.lang.reflect.Method;
/** /**
* 基础数据源创建器 * 基础数据源创建器
* *
@ -33,62 +34,62 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j @Slf4j
public class BasicDataSourceCreator { public class BasicDataSourceCreator {
private static Method createMethod; private static Method createMethod;
private static Method typeMethod; private static Method typeMethod;
private static Method urlMethod; private static Method urlMethod;
private static Method usernameMethod; private static Method usernameMethod;
private static Method passwordMethod; private static Method passwordMethod;
private static Method driverClassNameMethod; private static Method driverClassNameMethod;
private static Method buildMethod; private static Method buildMethod;
static { static {
//to support springboot 1.5 and 2.x //to support springboot 1.5 and 2.x
Class<?> builderClass = null; Class<?> builderClass = null;
try { try {
builderClass = Class.forName("org.springframework.boot.jdbc.DataSourceBuilder"); builderClass = Class.forName("org.springframework.boot.jdbc.DataSourceBuilder");
} catch (Exception ignored) { } catch (Exception ignored) {
}
if (builderClass == null) {
try {
builderClass = Class.forName("org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder");
} catch (Exception e) {
log.warn("not in springBoot ENV,could not create BasicDataSourceCreator");
}
}
if (builderClass != null) {
try {
createMethod = builderClass.getDeclaredMethod("create");
typeMethod = builderClass.getDeclaredMethod("type", Class.class);
urlMethod = builderClass.getDeclaredMethod("url", String.class);
usernameMethod = builderClass.getDeclaredMethod("username", String.class);
passwordMethod = builderClass.getDeclaredMethod("password", String.class);
driverClassNameMethod = builderClass.getDeclaredMethod("driverClassName", String.class);
buildMethod = builderClass.getDeclaredMethod("build");
} catch (Exception e) {
e.printStackTrace();
}
}
} }
if (builderClass == null) {
try {
builderClass = Class.forName("org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder");
} catch (Exception e) {
log.warn("not in springBoot ENV,could not create BasicDataSourceCreator");
}
}
if (builderClass != null) {
try {
createMethod = builderClass.getDeclaredMethod("create");
typeMethod = builderClass.getDeclaredMethod("type", Class.class);
urlMethod = builderClass.getDeclaredMethod("url", String.class);
usernameMethod = builderClass.getDeclaredMethod("username", String.class);
passwordMethod = builderClass.getDeclaredMethod("password", String.class);
driverClassNameMethod = builderClass.getDeclaredMethod("driverClassName", String.class);
buildMethod = builderClass.getDeclaredMethod("build");
} catch (Exception e) {
e.printStackTrace();
}
}
}
/** /**
* 创建基础数据源 * 创建基础数据源
* *
* @param dataSourceProperty 数据源参数 * @param dataSourceProperty 数据源参数
* @return 数据源 * @return 数据源
*/ */
public DataSource createDataSource(DataSourceProperty dataSourceProperty) { public DataSource createDataSource(DataSourceProperty dataSourceProperty) {
try { try {
Object o1 = createMethod.invoke(null); Object o1 = createMethod.invoke(null);
Object o2 = typeMethod.invoke(o1, dataSourceProperty.getType()); Object o2 = typeMethod.invoke(o1, dataSourceProperty.getType());
Object o3 = urlMethod.invoke(o2, dataSourceProperty.getUrl()); Object o3 = urlMethod.invoke(o2, dataSourceProperty.getUrl());
Object o4 = usernameMethod.invoke(o3, dataSourceProperty.getUsername()); Object o4 = usernameMethod.invoke(o3, dataSourceProperty.getUsername());
Object o5 = passwordMethod.invoke(o4, dataSourceProperty.getPassword()); Object o5 = passwordMethod.invoke(o4, dataSourceProperty.getPassword());
Object o6 = driverClassNameMethod.invoke(o5, dataSourceProperty.getDriverClassName()); Object o6 = driverClassNameMethod.invoke(o5, dataSourceProperty.getDriverClassName());
return (DataSource) buildMethod.invoke(o6); return (DataSource) buildMethod.invoke(o6);
} catch (Exception e) { } catch (Exception e) {
throw new ErrorCreateDataSourceException( throw new ErrorCreateDataSourceException(
"dynamic-datasource create basic database named " + dataSourceProperty.getPoolName() + " error"); "dynamic-datasource create basic database named " + dataSourceProperty.getPoolName() + " error");
}
} }
}
} }

View File

@ -16,16 +16,17 @@
*/ */
package com.baomidou.dynamic.datasource.creator; package com.baomidou.dynamic.datasource.creator;
import static com.baomidou.dynamic.datasource.support.DdConstants.DRUID_DATASOURCE;
import static com.baomidou.dynamic.datasource.support.DdConstants.HIKARI_DATASOURCE;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty; import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import com.baomidou.dynamic.datasource.support.ScriptRunner; import com.baomidou.dynamic.datasource.support.ScriptRunner;
import javax.sql.DataSource;
import lombok.Setter; import lombok.Setter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import javax.sql.DataSource;
import static com.baomidou.dynamic.datasource.support.DdConstants.DRUID_DATASOURCE;
import static com.baomidou.dynamic.datasource.support.DdConstants.HIKARI_DATASOURCE;
/** /**
* 数据源创建器 * 数据源创建器
* *
@ -36,129 +37,129 @@ import org.springframework.util.StringUtils;
@Setter @Setter
public class DataSourceCreator { public class DataSourceCreator {
/** /**
* 是否存在druid * 是否存在druid
*/ */
private static Boolean druidExists = false; private static Boolean druidExists = false;
/** /**
* 是否存在hikari * 是否存在hikari
*/ */
private static Boolean hikariExists = false; private static Boolean hikariExists = false;
static { static {
try { try {
Class.forName(DRUID_DATASOURCE); Class.forName(DRUID_DATASOURCE);
druidExists = true; druidExists = true;
} catch (ClassNotFoundException ignored) { } catch (ClassNotFoundException ignored) {
} }
try { try {
Class.forName(HIKARI_DATASOURCE); Class.forName(HIKARI_DATASOURCE);
hikariExists = true; hikariExists = true;
} catch (ClassNotFoundException ignored) { } catch (ClassNotFoundException ignored) {
}
}
private BasicDataSourceCreator basicDataSourceCreator;
private JndiDataSourceCreator jndiDataSourceCreator;
private HikariDataSourceCreator hikariDataSourceCreator;
private DruidDataSourceCreator druidDataSourceCreator;
private String globalPublicKey;
/**
* 创建数据源
*
* @param dataSourceProperty 数据源信息
* @return 数据源
*/
public DataSource createDataSource(DataSourceProperty dataSourceProperty) {
DataSource dataSource;
//如果是jndi数据源
String jndiName = dataSourceProperty.getJndiName();
if (jndiName != null && !jndiName.isEmpty()) {
dataSource = createJNDIDataSource(jndiName);
} else {
Class<? extends DataSource> type = dataSourceProperty.getType();
if (type == null) {
if (druidExists) {
dataSource = createDruidDataSource(dataSourceProperty);
} else if (hikariExists) {
dataSource = createHikariDataSource(dataSourceProperty);
} else {
dataSource = createBasicDataSource(dataSourceProperty);
} }
} else if (DRUID_DATASOURCE.equals(type.getName())) {
dataSource = createDruidDataSource(dataSourceProperty);
} else if (HIKARI_DATASOURCE.equals(type.getName())) {
dataSource = createHikariDataSource(dataSourceProperty);
} else {
dataSource = createBasicDataSource(dataSourceProperty);
}
} }
this.runScrip(dataSourceProperty, dataSource);
return dataSource;
}
private void runScrip(DataSourceProperty dataSourceProperty, DataSource dataSource) { private BasicDataSourceCreator basicDataSourceCreator;
String schema = dataSourceProperty.getSchema(); private JndiDataSourceCreator jndiDataSourceCreator;
String data = dataSourceProperty.getData(); private HikariDataSourceCreator hikariDataSourceCreator;
if (StringUtils.hasText(schema) || StringUtils.hasText(data)) { private DruidDataSourceCreator druidDataSourceCreator;
ScriptRunner scriptRunner = new ScriptRunner(dataSourceProperty.isContinueOnError(), dataSourceProperty.getSeparator()); private String globalPublicKey;
if (StringUtils.hasText(schema)) {
scriptRunner.runScript(dataSource, schema); /**
} * 创建数据源
if (StringUtils.hasText(data)) { *
scriptRunner.runScript(dataSource, data); * @param dataSourceProperty 数据源信息
} * @return 数据源
*/
public DataSource createDataSource(DataSourceProperty dataSourceProperty) {
DataSource dataSource;
//如果是jndi数据源
String jndiName = dataSourceProperty.getJndiName();
if (jndiName != null && !jndiName.isEmpty()) {
dataSource = createJNDIDataSource(jndiName);
} else {
Class<? extends DataSource> type = dataSourceProperty.getType();
if (type == null) {
if (druidExists) {
dataSource = createDruidDataSource(dataSourceProperty);
} else if (hikariExists) {
dataSource = createHikariDataSource(dataSourceProperty);
} else {
dataSource = createBasicDataSource(dataSourceProperty);
}
} else if (DRUID_DATASOURCE.equals(type.getName())) {
dataSource = createDruidDataSource(dataSourceProperty);
} else if (HIKARI_DATASOURCE.equals(type.getName())) {
dataSource = createHikariDataSource(dataSourceProperty);
} else {
dataSource = createBasicDataSource(dataSourceProperty);
}
}
this.runScrip(dataSourceProperty, dataSource);
return dataSource;
} }
}
/** private void runScrip(DataSourceProperty dataSourceProperty, DataSource dataSource) {
* 创建基础数据源 String schema = dataSourceProperty.getSchema();
* String data = dataSourceProperty.getData();
* @param dataSourceProperty 数据源参数 if (StringUtils.hasText(schema) || StringUtils.hasText(data)) {
* @return 数据源 ScriptRunner scriptRunner = new ScriptRunner(dataSourceProperty.isContinueOnError(), dataSourceProperty.getSeparator());
*/ if (StringUtils.hasText(schema)) {
public DataSource createBasicDataSource(DataSourceProperty dataSourceProperty) { scriptRunner.runScript(dataSource, schema);
if (StringUtils.isEmpty(dataSourceProperty.getPublicKey())) { }
dataSourceProperty.setPublicKey(globalPublicKey); if (StringUtils.hasText(data)) {
scriptRunner.runScript(dataSource, data);
}
}
} }
return basicDataSourceCreator.createDataSource(dataSourceProperty);
}
/** /**
* 创建JNDI数据源 * 创建基础数据源
* *
* @param jndiName jndi数据源名称 * @param dataSourceProperty 数据源参数
* @return 数据源 * @return 数据源
*/ */
public DataSource createJNDIDataSource(String jndiName) { public DataSource createBasicDataSource(DataSourceProperty dataSourceProperty) {
return jndiDataSourceCreator.createDataSource(jndiName); if (StringUtils.isEmpty(dataSourceProperty.getPublicKey())) {
} dataSourceProperty.setPublicKey(globalPublicKey);
}
/** return basicDataSourceCreator.createDataSource(dataSourceProperty);
* 创建Druid数据源
*
* @param dataSourceProperty 数据源参数
* @return 数据源
*/
public DataSource createDruidDataSource(DataSourceProperty dataSourceProperty) {
if (StringUtils.isEmpty(dataSourceProperty.getPublicKey())) {
dataSourceProperty.setPublicKey(globalPublicKey);
} }
return druidDataSourceCreator.createDataSource(dataSourceProperty);
}
/** /**
* 创建Hikari数据源 * 创建JNDI数据源
* *
* @param dataSourceProperty 数据源参数 * @param jndiName jndi数据源名称
* @return 数据源 * @return 数据源
* @author 离世庭院 小锅盖 */
*/ public DataSource createJNDIDataSource(String jndiName) {
public DataSource createHikariDataSource(DataSourceProperty dataSourceProperty) { return jndiDataSourceCreator.createDataSource(jndiName);
if (StringUtils.isEmpty(dataSourceProperty.getPublicKey())) { }
dataSourceProperty.setPublicKey(globalPublicKey);
/**
* 创建Druid数据源
*
* @param dataSourceProperty 数据源参数
* @return 数据源
*/
public DataSource createDruidDataSource(DataSourceProperty dataSourceProperty) {
if (StringUtils.isEmpty(dataSourceProperty.getPublicKey())) {
dataSourceProperty.setPublicKey(globalPublicKey);
}
return druidDataSourceCreator.createDataSource(dataSourceProperty);
}
/**
* 创建Hikari数据源
*
* @param dataSourceProperty 数据源参数
* @return 数据源
* @author 离世庭院 小锅盖
*/
public DataSource createHikariDataSource(DataSourceProperty dataSourceProperty) {
if (StringUtils.isEmpty(dataSourceProperty.getPublicKey())) {
dataSourceProperty.setPublicKey(globalPublicKey);
}
return hikariDataSourceCreator.createDataSource(dataSourceProperty);
} }
return hikariDataSourceCreator.createDataSource(dataSourceProperty);
}
} }

View File

@ -27,16 +27,17 @@ import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourcePrope
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig; import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidSlf4jConfig; import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidSlf4jConfig;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidWallConfigUtil; import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidWallConfigUtil;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import javax.sql.DataSource;
import lombok.Data; import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
/** /**
* Druid数据源创建器 * Druid数据源创建器
* *
@ -46,115 +47,115 @@ import org.springframework.util.StringUtils;
@Data @Data
public class DruidDataSourceCreator { public class DruidDataSourceCreator {
private DruidConfig druidConfig; private DruidConfig druidConfig;
@Autowired(required = false) @Autowired(required = false)
private ApplicationContext applicationContext; private ApplicationContext applicationContext;
public DruidDataSourceCreator(DruidConfig druidConfig) { public DruidDataSourceCreator(DruidConfig druidConfig) {
this.druidConfig = druidConfig; this.druidConfig = druidConfig;
}
public DataSource createDataSource(DataSourceProperty dataSourceProperty) {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUsername(dataSourceProperty.getUsername());
dataSource.setPassword(dataSourceProperty.getPassword());
dataSource.setUrl(dataSourceProperty.getUrl());
dataSource.setDriverClassName(dataSourceProperty.getDriverClassName());
dataSource.setName(dataSourceProperty.getPoolName());
DruidConfig config = dataSourceProperty.getDruid();
Properties properties = config.toProperties(druidConfig);
String filters = properties.getProperty("druid.filters");
List<Filter> proxyFilters = new ArrayList<>(2);
if (!StringUtils.isEmpty(filters) && filters.contains("stat")) {
StatFilter statFilter = new StatFilter();
statFilter.configFromProperties(properties);
proxyFilters.add(statFilter);
}
if (!StringUtils.isEmpty(filters) && filters.contains("wall")) {
WallConfig wallConfig = DruidWallConfigUtil.toWallConfig(dataSourceProperty.getDruid().getWall(), druidConfig.getWall());
WallFilter wallFilter = new WallFilter();
wallFilter.setConfig(wallConfig);
proxyFilters.add(wallFilter);
}
if (!StringUtils.isEmpty(filters) && filters.contains("slf4j")) {
Slf4jLogFilter slf4jLogFilter = new Slf4jLogFilter();
// 由于properties上面被用了LogFilter不能使用configFromProperties方法这里只能一个个set了
DruidSlf4jConfig slf4jConfig = druidConfig.getSlf4j();
slf4jLogFilter.setStatementLogEnabled(slf4jConfig.getEnable());
slf4jLogFilter.setStatementExecutableSqlLogEnable(slf4jConfig.getStatementExecutableSqlLogEnable());
proxyFilters.add(slf4jLogFilter);
} }
if (this.applicationContext != null) { public DataSource createDataSource(DataSourceProperty dataSourceProperty) {
for (String filterId : druidConfig.getProxyFilters()) { DruidDataSource dataSource = new DruidDataSource();
proxyFilters.add(this.applicationContext.getBean(filterId, Filter.class)); dataSource.setUsername(dataSourceProperty.getUsername());
} dataSource.setPassword(dataSourceProperty.getPassword());
} dataSource.setUrl(dataSourceProperty.getUrl());
dataSource.setProxyFilters(proxyFilters); dataSource.setDriverClassName(dataSourceProperty.getDriverClassName());
dataSource.configFromPropety(properties); dataSource.setName(dataSourceProperty.getPoolName());
//连接参数单独设置 DruidConfig config = dataSourceProperty.getDruid();
dataSource.setConnectProperties(config.getConnectionProperties()); Properties properties = config.toProperties(druidConfig);
//设置druid内置properties不支持的的参数 String filters = properties.getProperty("druid.filters");
Boolean testOnReturn = config.getTestOnReturn() == null ? druidConfig.getTestOnReturn() : config.getTestOnReturn(); List<Filter> proxyFilters = new ArrayList<>(2);
if (testOnReturn != null && testOnReturn.equals(true)) { if (!StringUtils.isEmpty(filters) && filters.contains("stat")) {
dataSource.setTestOnReturn(true); StatFilter statFilter = new StatFilter();
} statFilter.configFromProperties(properties);
Integer validationQueryTimeout = proxyFilters.add(statFilter);
config.getValidationQueryTimeout() == null ? druidConfig.getValidationQueryTimeout() : config.getValidationQueryTimeout(); }
if (validationQueryTimeout != null && !validationQueryTimeout.equals(-1)) { if (!StringUtils.isEmpty(filters) && filters.contains("wall")) {
dataSource.setValidationQueryTimeout(validationQueryTimeout); WallConfig wallConfig = DruidWallConfigUtil.toWallConfig(dataSourceProperty.getDruid().getWall(), druidConfig.getWall());
} WallFilter wallFilter = new WallFilter();
wallFilter.setConfig(wallConfig);
proxyFilters.add(wallFilter);
}
if (!StringUtils.isEmpty(filters) && filters.contains("slf4j")) {
Slf4jLogFilter slf4jLogFilter = new Slf4jLogFilter();
// 由于properties上面被用了LogFilter不能使用configFromProperties方法这里只能一个个set了
DruidSlf4jConfig slf4jConfig = druidConfig.getSlf4j();
slf4jLogFilter.setStatementLogEnabled(slf4jConfig.getEnable());
slf4jLogFilter.setStatementExecutableSqlLogEnable(slf4jConfig.getStatementExecutableSqlLogEnable());
proxyFilters.add(slf4jLogFilter);
}
Boolean sharePreparedStatements = if (this.applicationContext != null) {
config.getSharePreparedStatements() == null ? druidConfig.getSharePreparedStatements() : config.getSharePreparedStatements(); for (String filterId : druidConfig.getProxyFilters()) {
if (sharePreparedStatements != null && sharePreparedStatements.equals(true)) { proxyFilters.add(this.applicationContext.getBean(filterId, Filter.class));
dataSource.setSharePreparedStatements(true); }
} }
Integer connectionErrorRetryAttempts = dataSource.setProxyFilters(proxyFilters);
config.getConnectionErrorRetryAttempts() == null ? druidConfig.getConnectionErrorRetryAttempts() dataSource.configFromPropety(properties);
: config.getConnectionErrorRetryAttempts(); //连接参数单独设置
if (connectionErrorRetryAttempts != null && !connectionErrorRetryAttempts.equals(1)) { dataSource.setConnectProperties(config.getConnectionProperties());
dataSource.setConnectionErrorRetryAttempts(connectionErrorRetryAttempts); //设置druid内置properties不支持的的参数
} Boolean testOnReturn = config.getTestOnReturn() == null ? druidConfig.getTestOnReturn() : config.getTestOnReturn();
Boolean breakAfterAcquireFailure = if (testOnReturn != null && testOnReturn.equals(true)) {
config.getBreakAfterAcquireFailure() == null ? druidConfig.getBreakAfterAcquireFailure() : config.getBreakAfterAcquireFailure(); dataSource.setTestOnReturn(true);
if (breakAfterAcquireFailure != null && breakAfterAcquireFailure.equals(true)) { }
dataSource.setBreakAfterAcquireFailure(true); Integer validationQueryTimeout =
} config.getValidationQueryTimeout() == null ? druidConfig.getValidationQueryTimeout() : config.getValidationQueryTimeout();
if (validationQueryTimeout != null && !validationQueryTimeout.equals(-1)) {
dataSource.setValidationQueryTimeout(validationQueryTimeout);
}
Integer timeout = config.getRemoveAbandonedTimeoutMillis() == null ? druidConfig.getRemoveAbandonedTimeoutMillis() Boolean sharePreparedStatements =
: config.getRemoveAbandonedTimeoutMillis(); config.getSharePreparedStatements() == null ? druidConfig.getSharePreparedStatements() : config.getSharePreparedStatements();
if (timeout != null) { if (sharePreparedStatements != null && sharePreparedStatements.equals(true)) {
dataSource.setRemoveAbandonedTimeout(timeout); dataSource.setSharePreparedStatements(true);
} }
Integer connectionErrorRetryAttempts =
config.getConnectionErrorRetryAttempts() == null ? druidConfig.getConnectionErrorRetryAttempts()
: config.getConnectionErrorRetryAttempts();
if (connectionErrorRetryAttempts != null && !connectionErrorRetryAttempts.equals(1)) {
dataSource.setConnectionErrorRetryAttempts(connectionErrorRetryAttempts);
}
Boolean breakAfterAcquireFailure =
config.getBreakAfterAcquireFailure() == null ? druidConfig.getBreakAfterAcquireFailure() : config.getBreakAfterAcquireFailure();
if (breakAfterAcquireFailure != null && breakAfterAcquireFailure.equals(true)) {
dataSource.setBreakAfterAcquireFailure(true);
}
Boolean abandoned = config.getRemoveAbandoned() == null ? druidConfig.getRemoveAbandoned() : config.getRemoveAbandoned(); Integer timeout = config.getRemoveAbandonedTimeoutMillis() == null ? druidConfig.getRemoveAbandonedTimeoutMillis()
if (abandoned != null) { : config.getRemoveAbandonedTimeoutMillis();
dataSource.setRemoveAbandoned(abandoned); if (timeout != null) {
} dataSource.setRemoveAbandonedTimeout(timeout);
}
Boolean logAbandoned = config.getLogAbandoned() == null ? druidConfig.getLogAbandoned() : config.getLogAbandoned(); Boolean abandoned = config.getRemoveAbandoned() == null ? druidConfig.getRemoveAbandoned() : config.getRemoveAbandoned();
if (logAbandoned != null) { if (abandoned != null) {
dataSource.setLogAbandoned(logAbandoned); dataSource.setRemoveAbandoned(abandoned);
} }
Integer queryTimeOut = config.getQueryTimeout() == null ? druidConfig.getQueryTimeout() : config.getQueryTimeout(); Boolean logAbandoned = config.getLogAbandoned() == null ? druidConfig.getLogAbandoned() : config.getLogAbandoned();
if (queryTimeOut != null) { if (logAbandoned != null) {
dataSource.setQueryTimeout(queryTimeOut); dataSource.setLogAbandoned(logAbandoned);
} }
Integer transactionQueryTimeout = Integer queryTimeOut = config.getQueryTimeout() == null ? druidConfig.getQueryTimeout() : config.getQueryTimeout();
config.getTransactionQueryTimeout() == null ? druidConfig.getTransactionQueryTimeout() : config.getTransactionQueryTimeout(); if (queryTimeOut != null) {
if (transactionQueryTimeout != null) { dataSource.setQueryTimeout(queryTimeOut);
dataSource.setTransactionQueryTimeout(transactionQueryTimeout); }
}
try { Integer transactionQueryTimeout =
dataSource.init(); config.getTransactionQueryTimeout() == null ? druidConfig.getTransactionQueryTimeout() : config.getTransactionQueryTimeout();
} catch (SQLException e) { if (transactionQueryTimeout != null) {
throw new ErrorCreateDataSourceException("druid create error", e); dataSource.setTransactionQueryTimeout(transactionQueryTimeout);
}
try {
dataSource.init();
} catch (SQLException e) {
throw new ErrorCreateDataSourceException("druid create error", e);
}
return dataSource;
} }
return dataSource;
}
} }

View File

@ -20,10 +20,11 @@ import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourcePrope
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.hikari.HikariCpConfig; import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.hikari.HikariCpConfig;
import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.HikariDataSource;
import javax.sql.DataSource;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import javax.sql.DataSource;
/** /**
* Hikari数据源创建器 * Hikari数据源创建器
* *
@ -34,15 +35,15 @@ import lombok.Data;
@AllArgsConstructor @AllArgsConstructor
public class HikariDataSourceCreator { public class HikariDataSourceCreator {
private HikariCpConfig hikariCpConfig; private HikariCpConfig hikariCpConfig;
public DataSource createDataSource(DataSourceProperty dataSourceProperty) { public DataSource createDataSource(DataSourceProperty dataSourceProperty) {
HikariConfig config = dataSourceProperty.getHikari().toHikariConfig(hikariCpConfig); HikariConfig config = dataSourceProperty.getHikari().toHikariConfig(hikariCpConfig);
config.setUsername(dataSourceProperty.getUsername()); config.setUsername(dataSourceProperty.getUsername());
config.setPassword(dataSourceProperty.getPassword()); config.setPassword(dataSourceProperty.getPassword());
config.setJdbcUrl(dataSourceProperty.getUrl()); config.setJdbcUrl(dataSourceProperty.getUrl());
config.setDriverClassName(dataSourceProperty.getDriverClassName()); config.setDriverClassName(dataSourceProperty.getDriverClassName());
config.setPoolName(dataSourceProperty.getPoolName()); config.setPoolName(dataSourceProperty.getPoolName());
return new HikariDataSource(config); return new HikariDataSource(config);
} }
} }

View File

@ -16,9 +16,10 @@
*/ */
package com.baomidou.dynamic.datasource.creator; package com.baomidou.dynamic.datasource.creator;
import javax.sql.DataSource;
import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup; import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;
import javax.sql.DataSource;
/** /**
* JNDI数据源创建器 * JNDI数据源创建器
* *
@ -27,16 +28,16 @@ import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;
*/ */
public class JndiDataSourceCreator { public class JndiDataSourceCreator {
private static final JndiDataSourceLookup LOOKUP = new JndiDataSourceLookup(); private static final JndiDataSourceLookup LOOKUP = new JndiDataSourceLookup();
/** /**
* 创建基础数据源 * 创建基础数据源
* *
* @param name 数据源参数 * @param name 数据源参数
* @return 数据源 * @return 数据源
*/ */
public DataSource createDataSource(String name) { public DataSource createDataSource(String name) {
return LOOKUP.getDataSource(name); return LOOKUP.getDataSource(name);
} }
} }

View File

@ -24,11 +24,11 @@ package com.baomidou.dynamic.datasource.exception;
*/ */
public class ErrorCreateDataSourceException extends RuntimeException { public class ErrorCreateDataSourceException extends RuntimeException {
public ErrorCreateDataSourceException(String message) { public ErrorCreateDataSourceException(String message) {
super(message); super(message);
} }
public ErrorCreateDataSourceException(String message, Throwable cause) { public ErrorCreateDataSourceException(String message, Throwable cause) {
super(message, cause); super(message, cause);
} }
} }

View File

@ -27,7 +27,7 @@ import lombok.Data;
@Data @Data
public class ExpressionMatcher implements Matcher { public class ExpressionMatcher implements Matcher {
private String expression; private String expression;
private String ds; private String ds;
} }

View File

@ -27,8 +27,8 @@ import lombok.Data;
@Data @Data
public class RegexMatcher implements Matcher { public class RegexMatcher implements Matcher {
private String pattern; private String pattern;
private String ds; private String ds;
} }

View File

@ -20,21 +20,18 @@ import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSour
import com.baomidou.dynamic.datasource.support.DbHealthIndicator; import com.baomidou.dynamic.datasource.support.DbHealthIndicator;
import com.baomidou.dynamic.datasource.support.DdConstants; import com.baomidou.dynamic.datasource.support.DdConstants;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder; import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import java.util.Properties;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.Executor; import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType; import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor; import org.apache.ibatis.plugin.*;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds; import org.apache.ibatis.session.RowBounds;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import java.util.Properties;
/** /**
* Master-slave Separation Plugin with mybatis * Master-slave Separation Plugin with mybatis
* *
@ -42,61 +39,61 @@ import org.springframework.util.StringUtils;
* @since 2.5.1 * @since 2.5.1
*/ */
@Intercepts({ @Intercepts({
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}), @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})}) @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})})
@Slf4j @Slf4j
public class MasterSlaveAutoRoutingPlugin implements Interceptor { public class MasterSlaveAutoRoutingPlugin implements Interceptor {
@Autowired @Autowired
private DynamicDataSourceProperties properties; private DynamicDataSourceProperties properties;
@Override @Override
public Object intercept(Invocation invocation) throws Throwable { public Object intercept(Invocation invocation) throws Throwable {
Object[] args = invocation.getArgs(); Object[] args = invocation.getArgs();
MappedStatement ms = (MappedStatement) args[0]; MappedStatement ms = (MappedStatement) args[0];
boolean empty = true; boolean empty = true;
try { try {
empty = StringUtils.isEmpty(DynamicDataSourceContextHolder.peek()); empty = StringUtils.isEmpty(DynamicDataSourceContextHolder.peek());
if (empty) { if (empty) {
DynamicDataSourceContextHolder.push(getDataSource(ms)); DynamicDataSourceContextHolder.push(getDataSource(ms));
} }
return invocation.proceed(); return invocation.proceed();
} finally { } finally {
if (empty) { if (empty) {
DynamicDataSourceContextHolder.clear(); DynamicDataSourceContextHolder.clear();
} }
}
}
/**
* 获取动态数据源名称重写注入 DbHealthIndicator 支持数据源健康状况判断选择
*
* @param mappedStatement mybatis MappedStatement
* @return 获取真实的数据源名称
*/
public String getDataSource(MappedStatement mappedStatement) {
String slave = DdConstants.SLAVE;
if (properties.isHealth()) {
/*
* 根据从库健康状况判断是否切到主库
*/
boolean health = DbHealthIndicator.getDbHealth(DdConstants.SLAVE);
if (!health) {
health = DbHealthIndicator.getDbHealth(DdConstants.MASTER);
if (health) {
slave = DdConstants.MASTER;
} }
}
} }
return SqlCommandType.SELECT == mappedStatement.getSqlCommandType() ? slave : DdConstants.MASTER;
}
@Override /**
public Object plugin(Object target) { * 获取动态数据源名称重写注入 DbHealthIndicator 支持数据源健康状况判断选择
return target instanceof Executor ? Plugin.wrap(target, this) : target; *
} * @param mappedStatement mybatis MappedStatement
* @return 获取真实的数据源名称
*/
public String getDataSource(MappedStatement mappedStatement) {
String slave = DdConstants.SLAVE;
if (properties.isHealth()) {
/*
* 根据从库健康状况判断是否切到主库
*/
boolean health = DbHealthIndicator.getDbHealth(DdConstants.SLAVE);
if (!health) {
health = DbHealthIndicator.getDbHealth(DdConstants.MASTER);
if (health) {
slave = DdConstants.MASTER;
}
}
}
return SqlCommandType.SELECT == mappedStatement.getSqlCommandType() ? slave : DdConstants.MASTER;
}
@Override @Override
public void setProperties(Properties properties) { public Object plugin(Object target) {
} return target instanceof Executor ? Plugin.wrap(target, this) : target;
}
@Override
public void setProperties(Properties properties) {
}
} }

View File

@ -16,30 +16,31 @@
*/ */
package com.baomidou.dynamic.datasource.processor; package com.baomidou.dynamic.datasource.processor;
import javax.servlet.http.HttpServletRequest;
import org.aopalliance.intercept.MethodInvocation; import org.aopalliance.intercept.MethodInvocation;
import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
/** /**
* @author TaoYu * @author TaoYu
* @since 2.5.0 * @since 2.5.0
*/ */
public class DsHeaderProcessor extends DsProcessor { public class DsHeaderProcessor extends DsProcessor {
/** /**
* header prefix * header prefix
*/ */
private static final String HEADER_PREFIX = "#header"; private static final String HEADER_PREFIX = "#header";
@Override @Override
public boolean matches(String key) { public boolean matches(String key) {
return key.startsWith(HEADER_PREFIX); return key.startsWith(HEADER_PREFIX);
} }
@Override @Override
public String doDetermineDatasource(MethodInvocation invocation, String key) { public String doDetermineDatasource(MethodInvocation invocation, String key) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
return request.getHeader(key.substring(8)); return request.getHeader(key.substring(8));
} }
} }

View File

@ -24,51 +24,51 @@ import org.aopalliance.intercept.MethodInvocation;
*/ */
public abstract class DsProcessor { public abstract class DsProcessor {
private DsProcessor nextProcessor; private DsProcessor nextProcessor;
public void setNextProcessor(DsProcessor dsProcessor) { public void setNextProcessor(DsProcessor dsProcessor) {
this.nextProcessor = dsProcessor; this.nextProcessor = dsProcessor;
}
/**
* 抽象匹配条件 匹配才会走当前执行器否则走下一级执行器
*
* @param key DS注解里的内容
* @return 是否匹配
*/
public abstract boolean matches(String key);
/**
* 决定数据源
* <pre>
* 调用底层doDetermineDatasource
* 如果返回的是null则继续执行下一个否则直接返回
* </pre>
*
* @param invocation 方法执行信息
* @param key DS注解里的内容
* @return 数据源名称
*/
public String determineDatasource(MethodInvocation invocation, String key) {
if (matches(key)) {
String datasource = doDetermineDatasource(invocation, key);
if (datasource == null && nextProcessor != null) {
return nextProcessor.determineDatasource(invocation, key);
}
return datasource;
} }
if (nextProcessor != null) {
return nextProcessor.determineDatasource(invocation, key);
}
return null;
}
/** /**
* 抽象最终决定数据源 * 抽象匹配条件 匹配才会走当前执行器否则走下一级执行器
* *
* @param invocation 方法执行信息 * @param key DS注解里的内容
* @param key DS注解里的内容 * @return 是否匹配
* @return 数据源名称 */
*/ public abstract boolean matches(String key);
public abstract String doDetermineDatasource(MethodInvocation invocation, String key);
/**
* 决定数据源
* <pre>
* 调用底层doDetermineDatasource
* 如果返回的是null则继续执行下一个否则直接返回
* </pre>
*
* @param invocation 方法执行信息
* @param key DS注解里的内容
* @return 数据源名称
*/
public String determineDatasource(MethodInvocation invocation, String key) {
if (matches(key)) {
String datasource = doDetermineDatasource(invocation, key);
if (datasource == null && nextProcessor != null) {
return nextProcessor.determineDatasource(invocation, key);
}
return datasource;
}
if (nextProcessor != null) {
return nextProcessor.determineDatasource(invocation, key);
}
return null;
}
/**
* 抽象最终决定数据源
*
* @param invocation 方法执行信息
* @param key DS注解里的内容
* @return 数据源名称
*/
public abstract String doDetermineDatasource(MethodInvocation invocation, String key);
} }

View File

@ -16,30 +16,31 @@
*/ */
package com.baomidou.dynamic.datasource.processor; package com.baomidou.dynamic.datasource.processor;
import javax.servlet.http.HttpServletRequest;
import org.aopalliance.intercept.MethodInvocation; import org.aopalliance.intercept.MethodInvocation;
import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
/** /**
* @author TaoYu * @author TaoYu
* @since 2.5.0 * @since 2.5.0
*/ */
public class DsSessionProcessor extends DsProcessor { public class DsSessionProcessor extends DsProcessor {
/** /**
* session开头 * session开头
*/ */
private static final String SESSION_PREFIX = "#session"; private static final String SESSION_PREFIX = "#session";
@Override @Override
public boolean matches(String key) { public boolean matches(String key) {
return key.startsWith(SESSION_PREFIX); return key.startsWith(SESSION_PREFIX);
} }
@Override @Override
public String doDetermineDatasource(MethodInvocation invocation, String key) { public String doDetermineDatasource(MethodInvocation invocation, String key) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
return request.getSession().getAttribute(key.substring(9)).toString(); return request.getSession().getAttribute(key.substring(9)).toString();
} }
} }

View File

@ -16,7 +16,6 @@
*/ */
package com.baomidou.dynamic.datasource.processor; package com.baomidou.dynamic.datasource.processor;
import java.lang.reflect.Method;
import org.aopalliance.intercept.MethodInvocation; import org.aopalliance.intercept.MethodInvocation;
import org.springframework.context.expression.MethodBasedEvaluationContext; import org.springframework.context.expression.MethodBasedEvaluationContext;
import org.springframework.core.DefaultParameterNameDiscoverer; import org.springframework.core.DefaultParameterNameDiscoverer;
@ -26,44 +25,45 @@ import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParserContext; import org.springframework.expression.ParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser;
import java.lang.reflect.Method;
/** /**
* @author TaoYu * @author TaoYu
* @since 2.5.0 * @since 2.5.0
*/ */
public class DsSpelExpressionProcessor extends DsProcessor { public class DsSpelExpressionProcessor extends DsProcessor {
/** /**
* 参数发现器 * 参数发现器
*/ */
private static final ParameterNameDiscoverer NAME_DISCOVERER = new DefaultParameterNameDiscoverer(); private static final ParameterNameDiscoverer NAME_DISCOVERER = new DefaultParameterNameDiscoverer();
/** /**
* Express语法解析器 * Express语法解析器
*/ */
private static final ExpressionParser PARSER = new SpelExpressionParser(); private static final ExpressionParser PARSER = new SpelExpressionParser();
/**
* 解析上下文的模板
* 对于默认不设置的情况下,从参数中取值的方式 #param1
* 设置指定模板 ParserContext.TEMPLATE_EXPRESSION 后的取值方式: #{#param1}
* issues: https://github.com/baomidou/dynamic-datasource-spring-boot-starter/issues/199
*/
private ParserContext parserContext = null;
@Override @Override
public boolean matches(String key) { public boolean matches(String key) {
return true; return true;
} }
/** @Override
* 解析上下文的模板 public String doDetermineDatasource(MethodInvocation invocation, String key) {
* 对于默认不设置的情况下,从参数中取值的方式 #param1 Method method = invocation.getMethod();
* 设置指定模板 ParserContext.TEMPLATE_EXPRESSION 后的取值方式: #{#param1} Object[] arguments = invocation.getArguments();
* issues: https://github.com/baomidou/dynamic-datasource-spring-boot-starter/issues/199 EvaluationContext context = new MethodBasedEvaluationContext(null, method, arguments, NAME_DISCOVERER);
*/ final Object value = PARSER.parseExpression(key, parserContext).getValue(context);
private ParserContext parserContext = null; return value == null ? null : value.toString();
}
@Override public void setParserContext(ParserContext parserContext) {
public String doDetermineDatasource(MethodInvocation invocation, String key) { this.parserContext = parserContext;
Method method = invocation.getMethod(); }
Object[] arguments = invocation.getArguments();
EvaluationContext context = new MethodBasedEvaluationContext(null, method, arguments, NAME_DISCOVERER);
final Object value = PARSER.parseExpression(key,parserContext).getValue(context);
return value == null ? null : value.toString();
}
public void setParserContext(ParserContext parserContext) {
this.parserContext = parserContext;
}
} }

View File

@ -18,31 +18,32 @@ package com.baomidou.dynamic.datasource.provider;
import com.baomidou.dynamic.datasource.creator.DataSourceCreator; import com.baomidou.dynamic.datasource.creator.DataSourceCreator;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty; import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
@Slf4j @Slf4j
public abstract class AbstractDataSourceProvider implements DynamicDataSourceProvider { public abstract class AbstractDataSourceProvider implements DynamicDataSourceProvider {
@Autowired @Autowired
private DataSourceCreator dataSourceCreator; private DataSourceCreator dataSourceCreator;
protected Map<String, DataSource> createDataSourceMap( protected Map<String, DataSource> createDataSourceMap(
Map<String, DataSourceProperty> dataSourcePropertiesMap) { Map<String, DataSourceProperty> dataSourcePropertiesMap) {
Map<String, DataSource> dataSourceMap = new HashMap<>(dataSourcePropertiesMap.size() * 2); Map<String, DataSource> dataSourceMap = new HashMap<>(dataSourcePropertiesMap.size() * 2);
for (Map.Entry<String, DataSourceProperty> item : dataSourcePropertiesMap.entrySet()) { for (Map.Entry<String, DataSourceProperty> item : dataSourcePropertiesMap.entrySet()) {
DataSourceProperty dataSourceProperty = item.getValue(); DataSourceProperty dataSourceProperty = item.getValue();
String pollName = dataSourceProperty.getPoolName(); String pollName = dataSourceProperty.getPoolName();
if (pollName == null || "".equals(pollName)) { if (pollName == null || "".equals(pollName)) {
pollName = item.getKey(); pollName = item.getKey();
} }
dataSourceProperty.setPoolName(pollName); dataSourceProperty.setPoolName(pollName);
dataSourceMap.put(pollName, dataSourceCreator.createDataSource(dataSourceProperty)); dataSourceMap.put(pollName, dataSourceCreator.createDataSource(dataSourceProperty));
}
return dataSourceMap;
} }
return dataSourceMap;
}
} }

View File

@ -17,14 +17,15 @@
package com.baomidou.dynamic.datasource.provider; package com.baomidou.dynamic.datasource.provider;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty; import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.support.JdbcUtils;
import javax.sql.DataSource;
import java.sql.Connection; import java.sql.Connection;
import java.sql.DriverManager; import java.sql.DriverManager;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.util.Map; import java.util.Map;
import javax.sql.DataSource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.support.JdbcUtils;
/** /**
* JDBC数据源提供者(抽象) * JDBC数据源提供者(抽象)
@ -35,58 +36,58 @@ import org.springframework.jdbc.support.JdbcUtils;
@Slf4j @Slf4j
public abstract class AbstractJdbcDataSourceProvider extends AbstractDataSourceProvider implements DynamicDataSourceProvider { public abstract class AbstractJdbcDataSourceProvider extends AbstractDataSourceProvider implements DynamicDataSourceProvider {
/** /**
* JDBC driver * JDBC driver
*/ */
private String driverClassName; private String driverClassName;
/** /**
* JDBC url 地址 * JDBC url 地址
*/ */
private String url; private String url;
/** /**
* JDBC 用户名 * JDBC 用户名
*/ */
private String username; private String username;
/** /**
* JDBC 密码 * JDBC 密码
*/ */
private String password; private String password;
public AbstractJdbcDataSourceProvider(String driverClassName, String url, String username, String password) { public AbstractJdbcDataSourceProvider(String driverClassName, String url, String username, String password) {
this.driverClassName = driverClassName; this.driverClassName = driverClassName;
this.url = url; this.url = url;
this.username = username; this.username = username;
this.password = password; this.password = password;
}
@Override
public Map<String, DataSource> loadDataSources() {
Connection conn = null;
Statement stmt = null;
try {
Class.forName(driverClassName);
log.info("成功加载数据库驱动程序");
conn = DriverManager.getConnection(url, username, password);
log.info("成功获取数据库连接");
stmt = conn.createStatement();
Map<String, DataSourceProperty> dataSourcePropertiesMap = executeStmt(stmt);
return createDataSourceMap(dataSourcePropertiesMap);
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtils.closeConnection(conn);
JdbcUtils.closeStatement(stmt);
} }
return null;
}
/** @Override
* 执行语句获得数据源参数 public Map<String, DataSource> loadDataSources() {
* Connection conn = null;
* @param statement 语句 Statement stmt = null;
* @return 数据源参数 try {
* @throws SQLException sql异常 Class.forName(driverClassName);
*/ log.info("成功加载数据库驱动程序");
protected abstract Map<String, DataSourceProperty> executeStmt(Statement statement) conn = DriverManager.getConnection(url, username, password);
throws SQLException; log.info("成功获取数据库连接");
stmt = conn.createStatement();
Map<String, DataSourceProperty> dataSourcePropertiesMap = executeStmt(stmt);
return createDataSourceMap(dataSourcePropertiesMap);
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtils.closeConnection(conn);
JdbcUtils.closeStatement(stmt);
}
return null;
}
/**
* 执行语句获得数据源参数
*
* @param statement 语句
* @return 数据源参数
* @throws SQLException sql异常
*/
protected abstract Map<String, DataSourceProperty> executeStmt(Statement statement)
throws SQLException;
} }

View File

@ -16,8 +16,8 @@
*/ */
package com.baomidou.dynamic.datasource.provider; package com.baomidou.dynamic.datasource.provider;
import java.util.Map;
import javax.sql.DataSource; import javax.sql.DataSource;
import java.util.Map;
/** /**
* 多数据源加载接口默认的实现为从yml信息中加载所有数据源 你可以自己实现从其他地方加载所有数据源 * 多数据源加载接口默认的实现为从yml信息中加载所有数据源 你可以自己实现从其他地方加载所有数据源
@ -29,10 +29,10 @@ import javax.sql.DataSource;
*/ */
public interface DynamicDataSourceProvider { public interface DynamicDataSourceProvider {
/** /**
* 加载所有数据源 * 加载所有数据源
* *
* @return 所有数据源key为数据源名称 * @return 所有数据源key为数据源名称
*/ */
Map<String, DataSource> loadDataSources(); Map<String, DataSource> loadDataSources();
} }

View File

@ -17,11 +17,12 @@
package com.baomidou.dynamic.datasource.provider; package com.baomidou.dynamic.datasource.provider;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty; import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import java.util.Map;
import javax.sql.DataSource;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import javax.sql.DataSource;
import java.util.Map;
/** /**
* YML数据源提供者 * YML数据源提供者
* *
@ -32,13 +33,13 @@ import lombok.extern.slf4j.Slf4j;
@AllArgsConstructor @AllArgsConstructor
public class YmlDynamicDataSourceProvider extends AbstractDataSourceProvider implements DynamicDataSourceProvider { public class YmlDynamicDataSourceProvider extends AbstractDataSourceProvider implements DynamicDataSourceProvider {
/** /**
* 所有数据源 * 所有数据源
*/ */
private Map<String, DataSourceProperty> dataSourcePropertiesMap; private Map<String, DataSourceProperty> dataSourcePropertiesMap;
@Override @Override
public Map<String, DataSource> loadDataSources() { public Map<String, DataSource> loadDataSources() {
return createDataSourceMap(dataSourcePropertiesMap); return createDataSourceMap(dataSourcePropertiesMap);
} }
} }

View File

@ -19,15 +19,16 @@ package com.baomidou.dynamic.datasource.spring.boot.autoconfigure;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig; import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.hikari.HikariCpConfig; import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.hikari.HikariCpConfig;
import com.baomidou.dynamic.datasource.toolkit.CryptoUtils; import com.baomidou.dynamic.datasource.toolkit.CryptoUtils;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.sql.DataSource;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.NestedConfigurationProperty; import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import javax.sql.DataSource;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** /**
* @author TaoYu * @author TaoYu
* @since 1.2.0 * @since 1.2.0
@ -37,97 +38,97 @@ import org.springframework.util.StringUtils;
@Accessors(chain = true) @Accessors(chain = true)
public class DataSourceProperty { public class DataSourceProperty {
/** /**
* 加密正则 * 加密正则
*/ */
private static final Pattern ENC_PATTERN = Pattern.compile("^ENC\\((.*)\\)$"); private static final Pattern ENC_PATTERN = Pattern.compile("^ENC\\((.*)\\)$");
/** /**
* 连接池名称(只是一个名称标识)</br> 默认是配置文件上的名称 * 连接池名称(只是一个名称标识)</br> 默认是配置文件上的名称
*/ */
private String poolName; private String poolName;
/** /**
* 连接池类型如果不设置自动查找 Druid > HikariCp * 连接池类型如果不设置自动查找 Druid > HikariCp
*/ */
private Class<? extends DataSource> type; private Class<? extends DataSource> type;
/** /**
* JDBC driver * JDBC driver
*/ */
private String driverClassName; private String driverClassName;
/** /**
* JDBC url 地址 * JDBC url 地址
*/ */
private String url; private String url;
/** /**
* JDBC 用户名 * JDBC 用户名
*/ */
private String username; private String username;
/** /**
* JDBC 密码 * JDBC 密码
*/ */
private String password; private String password;
/** /**
* jndi数据源名称(设置即表示启用) * jndi数据源名称(设置即表示启用)
*/ */
private String jndiName; private String jndiName;
/** /**
* 自动运行的建表脚本 * 自动运行的建表脚本
*/ */
private String schema; private String schema;
/** /**
* 自动运行的数据脚本 * 自动运行的数据脚本
*/ */
private String data; private String data;
/** /**
* 错误是否继续 默认 true * 错误是否继续 默认 true
*/ */
private boolean continueOnError = true; private boolean continueOnError = true;
/** /**
* 分隔符 默认 ; * 分隔符 默认 ;
*/ */
private String separator = ";"; private String separator = ";";
/** /**
* Druid参数配置 * Druid参数配置
*/ */
@NestedConfigurationProperty @NestedConfigurationProperty
private DruidConfig druid = new DruidConfig(); private DruidConfig druid = new DruidConfig();
/** /**
* HikariCp参数配置 * HikariCp参数配置
*/ */
@NestedConfigurationProperty @NestedConfigurationProperty
private HikariCpConfig hikari = new HikariCpConfig(); private HikariCpConfig hikari = new HikariCpConfig();
/** /**
* 解密公匙(如果未设置默认使用全局的) * 解密公匙(如果未设置默认使用全局的)
*/ */
private String publicKey; private String publicKey;
public String getUrl() { public String getUrl() {
return decrypt(url); return decrypt(url);
} }
public String getUsername() { public String getUsername() {
return decrypt(username); return decrypt(username);
} }
public String getPassword() { public String getPassword() {
return decrypt(password); return decrypt(password);
} }
/** /**
* 字符串解密 * 字符串解密
*/ */
private String decrypt(String cipherText) { private String decrypt(String cipherText) {
if (StringUtils.hasText(cipherText)) { if (StringUtils.hasText(cipherText)) {
Matcher matcher = ENC_PATTERN.matcher(cipherText); Matcher matcher = ENC_PATTERN.matcher(cipherText);
if (matcher.find()) { if (matcher.find()) {
try { try {
return CryptoUtils.decrypt(publicKey, matcher.group(1)); return CryptoUtils.decrypt(publicKey, matcher.group(1));
} catch (Exception e) { } catch (Exception e) {
log.error("DynamicDataSourceProperties.decrypt error ", e); log.error("DynamicDataSourceProperties.decrypt error ", e);
} }
} }
}
return cipherText;
} }
return cipherText;
}
} }

View File

@ -29,8 +29,6 @@ import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider;
import com.baomidou.dynamic.datasource.provider.YmlDynamicDataSourceProvider; import com.baomidou.dynamic.datasource.provider.YmlDynamicDataSourceProvider;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidDynamicDataSourceConfiguration; import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidDynamicDataSourceConfiguration;
import com.baomidou.dynamic.datasource.strategy.DynamicDataSourceStrategy; import com.baomidou.dynamic.datasource.strategy.DynamicDataSourceStrategy;
import java.util.Map;
import javax.sql.DataSource;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.AutoConfigureBefore;
@ -43,7 +41,9 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.expression.ParserContext;
import javax.sql.DataSource;
import java.util.Map;
/** /**
* 动态数据源核心自动配置类 * 动态数据源核心自动配置类
@ -63,55 +63,55 @@ import org.springframework.expression.ParserContext;
@ConditionalOnProperty(prefix = DynamicDataSourceProperties.PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true) @ConditionalOnProperty(prefix = DynamicDataSourceProperties.PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true)
public class DynamicDataSourceAutoConfiguration { public class DynamicDataSourceAutoConfiguration {
private final DynamicDataSourceProperties properties; private final DynamicDataSourceProperties properties;
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public DynamicDataSourceProvider dynamicDataSourceProvider() { public DynamicDataSourceProvider dynamicDataSourceProvider() {
Map<String, DataSourceProperty> datasourceMap = properties.getDatasource(); Map<String, DataSourceProperty> datasourceMap = properties.getDatasource();
return new YmlDynamicDataSourceProvider(datasourceMap); return new YmlDynamicDataSourceProvider(datasourceMap);
} }
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public DataSource dataSource(DynamicDataSourceProvider dynamicDataSourceProvider) { public DataSource dataSource(DynamicDataSourceProvider dynamicDataSourceProvider) {
DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource(); DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource();
dataSource.setPrimary(properties.getPrimary()); dataSource.setPrimary(properties.getPrimary());
dataSource.setStrict(properties.getStrict()); dataSource.setStrict(properties.getStrict());
dataSource.setStrategy(properties.getStrategy()); dataSource.setStrategy(properties.getStrategy());
dataSource.setProvider(dynamicDataSourceProvider); dataSource.setProvider(dynamicDataSourceProvider);
dataSource.setP6spy(properties.getP6spy()); dataSource.setP6spy(properties.getP6spy());
dataSource.setSeata(properties.getSeata()); dataSource.setSeata(properties.getSeata());
return dataSource; return dataSource;
} }
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public DynamicDataSourceAnnotationAdvisor dynamicDatasourceAnnotationAdvisor(DsProcessor dsProcessor) { public DynamicDataSourceAnnotationAdvisor dynamicDatasourceAnnotationAdvisor(DsProcessor dsProcessor) {
DynamicDataSourceAnnotationInterceptor interceptor = new DynamicDataSourceAnnotationInterceptor(); DynamicDataSourceAnnotationInterceptor interceptor = new DynamicDataSourceAnnotationInterceptor();
interceptor.setDsProcessor(dsProcessor); interceptor.setDsProcessor(dsProcessor);
DynamicDataSourceAnnotationAdvisor advisor = new DynamicDataSourceAnnotationAdvisor(interceptor); DynamicDataSourceAnnotationAdvisor advisor = new DynamicDataSourceAnnotationAdvisor(interceptor);
advisor.setOrder(properties.getOrder()); advisor.setOrder(properties.getOrder());
return advisor; return advisor;
} }
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public DsProcessor dsProcessor() { public DsProcessor dsProcessor() {
DsHeaderProcessor headerProcessor = new DsHeaderProcessor(); DsHeaderProcessor headerProcessor = new DsHeaderProcessor();
DsSessionProcessor sessionProcessor = new DsSessionProcessor(); DsSessionProcessor sessionProcessor = new DsSessionProcessor();
DsSpelExpressionProcessor spelExpressionProcessor = new DsSpelExpressionProcessor(); DsSpelExpressionProcessor spelExpressionProcessor = new DsSpelExpressionProcessor();
headerProcessor.setNextProcessor(sessionProcessor); headerProcessor.setNextProcessor(sessionProcessor);
sessionProcessor.setNextProcessor(spelExpressionProcessor); sessionProcessor.setNextProcessor(spelExpressionProcessor);
return headerProcessor; return headerProcessor;
} }
@Bean @Bean
@ConditionalOnBean(DynamicDataSourceConfigure.class) @ConditionalOnBean(DynamicDataSourceConfigure.class)
public DynamicDataSourceAdvisor dynamicAdvisor(DynamicDataSourceConfigure dynamicDataSourceConfigure, DsProcessor dsProcessor) { public DynamicDataSourceAdvisor dynamicAdvisor(DynamicDataSourceConfigure dynamicDataSourceConfigure, DsProcessor dsProcessor) {
DynamicDataSourceAdvisor advisor = new DynamicDataSourceAdvisor(dynamicDataSourceConfigure.getMatchers()); DynamicDataSourceAdvisor advisor = new DynamicDataSourceAdvisor(dynamicDataSourceConfigure.getMatchers());
advisor.setDsProcessor(dsProcessor); advisor.setDsProcessor(dsProcessor);
advisor.setOrder(Ordered.HIGHEST_PRECEDENCE); advisor.setOrder(Ordered.HIGHEST_PRECEDENCE);
return advisor; return advisor;
} }
} }

View File

@ -16,11 +16,7 @@
*/ */
package com.baomidou.dynamic.datasource.spring.boot.autoconfigure; package com.baomidou.dynamic.datasource.spring.boot.autoconfigure;
import com.baomidou.dynamic.datasource.creator.BasicDataSourceCreator; import com.baomidou.dynamic.datasource.creator.*;
import com.baomidou.dynamic.datasource.creator.DataSourceCreator;
import com.baomidou.dynamic.datasource.creator.DruidDataSourceCreator;
import com.baomidou.dynamic.datasource.creator.HikariDataSourceCreator;
import com.baomidou.dynamic.datasource.creator.JndiDataSourceCreator;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@ -34,41 +30,41 @@ import org.springframework.context.annotation.Configuration;
@EnableConfigurationProperties(DynamicDataSourceProperties.class) @EnableConfigurationProperties(DynamicDataSourceProperties.class)
public class DynamicDataSourceCreatorAutoConfiguration { public class DynamicDataSourceCreatorAutoConfiguration {
private final DynamicDataSourceProperties properties; private final DynamicDataSourceProperties properties;
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public DataSourceCreator dataSourceCreator() { public DataSourceCreator dataSourceCreator() {
DataSourceCreator dataSourceCreator = new DataSourceCreator(); DataSourceCreator dataSourceCreator = new DataSourceCreator();
dataSourceCreator.setBasicDataSourceCreator(basicDataSourceCreator()); dataSourceCreator.setBasicDataSourceCreator(basicDataSourceCreator());
dataSourceCreator.setJndiDataSourceCreator(jndiDataSourceCreator()); dataSourceCreator.setJndiDataSourceCreator(jndiDataSourceCreator());
dataSourceCreator.setDruidDataSourceCreator(druidDataSourceCreator()); dataSourceCreator.setDruidDataSourceCreator(druidDataSourceCreator());
dataSourceCreator.setHikariDataSourceCreator(hikariDataSourceCreator()); dataSourceCreator.setHikariDataSourceCreator(hikariDataSourceCreator());
dataSourceCreator.setGlobalPublicKey(properties.getPublicKey()); dataSourceCreator.setGlobalPublicKey(properties.getPublicKey());
return dataSourceCreator; return dataSourceCreator;
} }
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public BasicDataSourceCreator basicDataSourceCreator() { public BasicDataSourceCreator basicDataSourceCreator() {
return new BasicDataSourceCreator(); return new BasicDataSourceCreator();
} }
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public JndiDataSourceCreator jndiDataSourceCreator() { public JndiDataSourceCreator jndiDataSourceCreator() {
return new JndiDataSourceCreator(); return new JndiDataSourceCreator();
} }
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public DruidDataSourceCreator druidDataSourceCreator() { public DruidDataSourceCreator druidDataSourceCreator() {
return new DruidDataSourceCreator(properties.getDruid()); return new DruidDataSourceCreator(properties.getDruid());
} }
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public HikariDataSourceCreator hikariDataSourceCreator() { public HikariDataSourceCreator hikariDataSourceCreator() {
return new HikariDataSourceCreator(properties.getHikari()); return new HikariDataSourceCreator(properties.getHikari());
} }
} }

View File

@ -21,8 +21,6 @@ import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.hikari.HikariCp
import com.baomidou.dynamic.datasource.strategy.DynamicDataSourceStrategy; import com.baomidou.dynamic.datasource.strategy.DynamicDataSourceStrategy;
import com.baomidou.dynamic.datasource.strategy.LoadBalanceDynamicDataSourceStrategy; import com.baomidou.dynamic.datasource.strategy.LoadBalanceDynamicDataSourceStrategy;
import com.baomidou.dynamic.datasource.toolkit.CryptoUtils; import com.baomidou.dynamic.datasource.toolkit.CryptoUtils;
import java.util.LinkedHashMap;
import java.util.Map;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -31,6 +29,9 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty; import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import java.util.LinkedHashMap;
import java.util.Map;
/** /**
* DynamicDataSourceProperties * DynamicDataSourceProperties
* *
@ -44,54 +45,54 @@ import org.springframework.core.Ordered;
@ConfigurationProperties(prefix = DynamicDataSourceProperties.PREFIX) @ConfigurationProperties(prefix = DynamicDataSourceProperties.PREFIX)
public class DynamicDataSourceProperties { public class DynamicDataSourceProperties {
public static final String PREFIX = "spring.datasource.dynamic"; public static final String PREFIX = "spring.datasource.dynamic";
public static final String HEALTH = PREFIX + ".health"; public static final String HEALTH = PREFIX + ".health";
/** /**
* 必须设置默认的库,默认master * 必须设置默认的库,默认master
*/ */
private String primary = "master"; private String primary = "master";
/** /**
* 是否启用严格模式,默认不启动. 严格模式下未匹配到数据源直接报错, 非严格模式下则使用默认数据源primary所设置的数据源 * 是否启用严格模式,默认不启动. 严格模式下未匹配到数据源直接报错, 非严格模式下则使用默认数据源primary所设置的数据源
*/ */
private Boolean strict = false; private Boolean strict = false;
/** /**
* 是否使用p6spy输出默认不输出 * 是否使用p6spy输出默认不输出
*/ */
private Boolean p6spy = false; private Boolean p6spy = false;
/** /**
* 是否使用seata,默认不使用 * 是否使用seata,默认不使用
*/ */
private Boolean seata = false; private Boolean seata = false;
/** /**
* 是否使用 spring actuator 监控检查默认不检查 * 是否使用 spring actuator 监控检查默认不检查
*/ */
private boolean health = false; private boolean health = false;
/** /**
* 每一个数据源 * 每一个数据源
*/ */
private Map<String, DataSourceProperty> datasource = new LinkedHashMap<>(); private Map<String, DataSourceProperty> datasource = new LinkedHashMap<>();
/** /**
* 多数据源选择算法clazz默认负载均衡算法 * 多数据源选择算法clazz默认负载均衡算法
*/ */
private Class<? extends DynamicDataSourceStrategy> strategy = LoadBalanceDynamicDataSourceStrategy.class; private Class<? extends DynamicDataSourceStrategy> strategy = LoadBalanceDynamicDataSourceStrategy.class;
/** /**
* aop切面顺序默认优先级最高 * aop切面顺序默认优先级最高
*/ */
private Integer order = Ordered.HIGHEST_PRECEDENCE; private Integer order = Ordered.HIGHEST_PRECEDENCE;
/** /**
* Druid全局参数配置 * Druid全局参数配置
*/ */
@NestedConfigurationProperty @NestedConfigurationProperty
private DruidConfig druid = new DruidConfig(); private DruidConfig druid = new DruidConfig();
/** /**
* HikariCp全局参数配置 * HikariCp全局参数配置
*/ */
@NestedConfigurationProperty @NestedConfigurationProperty
private HikariCpConfig hikari = new HikariCpConfig(); private HikariCpConfig hikari = new HikariCpConfig();
/** /**
* 全局默认publicKey * 全局默认publicKey
*/ */
private String publicKey = CryptoUtils.DEFAULT_PUBLIC_KEY_STRING; private String publicKey = CryptoUtils.DEFAULT_PUBLIC_KEY_STRING;
} }

View File

@ -41,259 +41,259 @@ import static com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.Dr
@Slf4j @Slf4j
public class DruidConfig { public class DruidConfig {
private Integer initialSize; private Integer initialSize;
private Integer maxActive; private Integer maxActive;
private Integer minIdle; private Integer minIdle;
private Integer maxWait; private Integer maxWait;
private Long timeBetweenEvictionRunsMillis; private Long timeBetweenEvictionRunsMillis;
private Long timeBetweenLogStatsMillis; private Long timeBetweenLogStatsMillis;
private Integer statSqlMaxSize; private Integer statSqlMaxSize;
private Long minEvictableIdleTimeMillis; private Long minEvictableIdleTimeMillis;
private Long maxEvictableIdleTimeMillis; private Long maxEvictableIdleTimeMillis;
private Boolean testWhileIdle; private Boolean testWhileIdle;
private Boolean testOnBorrow; private Boolean testOnBorrow;
private Boolean testOnReturn; private Boolean testOnReturn;
private String validationQuery; private String validationQuery;
private Integer validationQueryTimeout; private Integer validationQueryTimeout;
private Boolean useGlobalDataSourceStat; private Boolean useGlobalDataSourceStat;
private Boolean asyncInit; private Boolean asyncInit;
private String filters; private String filters;
private Boolean clearFiltersEnable; private Boolean clearFiltersEnable;
private Boolean resetStatEnable; private Boolean resetStatEnable;
private Integer notFullTimeoutRetryCount; private Integer notFullTimeoutRetryCount;
private Integer maxWaitThreadCount; private Integer maxWaitThreadCount;
private Boolean failFast; private Boolean failFast;
private Long phyTimeoutMillis; private Long phyTimeoutMillis;
private Boolean keepAlive; private Boolean keepAlive;
private Boolean poolPreparedStatements; private Boolean poolPreparedStatements;
private Boolean initVariants; private Boolean initVariants;
private Boolean initGlobalVariants; private Boolean initGlobalVariants;
private Boolean useUnfairLock; private Boolean useUnfairLock;
private Boolean killWhenSocketReadTimeout; private Boolean killWhenSocketReadTimeout;
private Properties connectionProperties; private Properties connectionProperties;
private Integer maxPoolPreparedStatementPerConnectionSize; private Integer maxPoolPreparedStatementPerConnectionSize;
private String initConnectionSqls; private String initConnectionSqls;
private Boolean sharePreparedStatements; private Boolean sharePreparedStatements;
private Integer connectionErrorRetryAttempts; private Integer connectionErrorRetryAttempts;
private Boolean breakAfterAcquireFailure; private Boolean breakAfterAcquireFailure;
private Boolean removeAbandoned; private Boolean removeAbandoned;
private Integer removeAbandonedTimeoutMillis; private Integer removeAbandonedTimeoutMillis;
private Boolean logAbandoned; private Boolean logAbandoned;
private Integer queryTimeout; private Integer queryTimeout;
private Integer transactionQueryTimeout; private Integer transactionQueryTimeout;
private String publicKey; private String publicKey;
@NestedConfigurationProperty @NestedConfigurationProperty
private DruidWallConfig wall = new DruidWallConfig(); private DruidWallConfig wall = new DruidWallConfig();
@NestedConfigurationProperty @NestedConfigurationProperty
private DruidStatConfig stat = new DruidStatConfig(); private DruidStatConfig stat = new DruidStatConfig();
@NestedConfigurationProperty @NestedConfigurationProperty
private DruidSlf4jConfig slf4j = new DruidSlf4jConfig(); private DruidSlf4jConfig slf4j = new DruidSlf4jConfig();
private List<String> proxyFilters = new ArrayList<>(); private List<String> proxyFilters = new ArrayList<>();
/** /**
* 根据全局配置和本地配置结合转换为Properties * 根据全局配置和本地配置结合转换为Properties
* *
* @param g 全局配置 * @param g 全局配置
* @return Druid配置 * @return Druid配置
*/ */
public Properties toProperties(DruidConfig g) { public Properties toProperties(DruidConfig g) {
Properties properties = new Properties(); Properties properties = new Properties();
Integer initialSize = this.initialSize == null ? g.getInitialSize() : this.initialSize; Integer initialSize = this.initialSize == null ? g.getInitialSize() : this.initialSize;
if (initialSize != null && !initialSize.equals(DEFAULT_INITIAL_SIZE)) { if (initialSize != null && !initialSize.equals(DEFAULT_INITIAL_SIZE)) {
properties.setProperty(INITIAL_SIZE, String.valueOf(initialSize)); properties.setProperty(INITIAL_SIZE, String.valueOf(initialSize));
}
Integer maxActive = this.maxActive == null ? g.getMaxActive() : this.maxActive;
if (maxActive != null && !maxActive.equals(DEFAULT_MAX_WAIT)) {
properties.setProperty(MAX_ACTIVE, String.valueOf(maxActive));
}
Integer minIdle = this.minIdle == null ? g.getMinIdle() : this.minIdle;
if (minIdle != null && !minIdle.equals(DEFAULT_MIN_IDLE)) {
properties.setProperty(MIN_IDLE, String.valueOf(minIdle));
}
Integer maxWait = this.maxWait == null ? g.getMaxWait() : this.maxWait;
if (maxWait != null && !maxWait.equals(DEFAULT_MAX_WAIT)) {
properties.setProperty(MAX_WAIT, String.valueOf(maxWait));
}
Long timeBetweenEvictionRunsMillis =
this.timeBetweenEvictionRunsMillis == null ? g.getTimeBetweenEvictionRunsMillis() : this.timeBetweenEvictionRunsMillis;
if (timeBetweenEvictionRunsMillis != null && !timeBetweenEvictionRunsMillis.equals(DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS)) {
properties.setProperty(TIME_BETWEEN_EVICTION_RUNS_MILLIS, String.valueOf(timeBetweenEvictionRunsMillis));
}
Long timeBetweenLogStatsMillis =
this.timeBetweenLogStatsMillis == null ? g.getTimeBetweenLogStatsMillis() : this.timeBetweenLogStatsMillis;
if (timeBetweenLogStatsMillis != null && timeBetweenLogStatsMillis > 0) {
properties.setProperty(TIME_BETWEEN_LOG_STATS_MILLIS, String.valueOf(timeBetweenLogStatsMillis));
}
Long minEvictableIdleTimeMillis =
this.minEvictableIdleTimeMillis == null ? g.getMinEvictableIdleTimeMillis() : this.minEvictableIdleTimeMillis;
if (minEvictableIdleTimeMillis != null && !minEvictableIdleTimeMillis.equals(DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS)) {
properties.setProperty(MIN_EVICTABLE_IDLE_TIME_MILLIS, String.valueOf(minEvictableIdleTimeMillis));
}
Long maxEvictableIdleTimeMillis =
this.maxEvictableIdleTimeMillis == null ? g.getMaxEvictableIdleTimeMillis() : this.maxEvictableIdleTimeMillis;
if (maxEvictableIdleTimeMillis != null && !maxEvictableIdleTimeMillis.equals(DEFAULT_MAX_EVICTABLE_IDLE_TIME_MILLIS)) {
properties.setProperty(MAX_EVICTABLE_IDLE_TIME_MILLIS, String.valueOf(maxEvictableIdleTimeMillis));
}
Boolean testWhileIdle = this.testWhileIdle == null ? g.getTestWhileIdle() : this.testWhileIdle;
if (testWhileIdle != null && !testWhileIdle.equals(DEFAULT_WHILE_IDLE)) {
properties.setProperty(TEST_WHILE_IDLE, "false");
}
Boolean testOnBorrow = this.testOnBorrow == null ? g.getTestOnBorrow() : this.testOnBorrow;
if (testOnBorrow != null && !testOnBorrow.equals(DEFAULT_TEST_ON_BORROW)) {
properties.setProperty(TEST_ON_BORROW, "true");
}
String validationQuery = this.validationQuery == null ? g.getValidationQuery() : this.validationQuery;
if (validationQuery != null && validationQuery.length() > 0) {
properties.setProperty(VALIDATION_QUERY, validationQuery);
}
Boolean useGlobalDataSourceStat = this.useGlobalDataSourceStat == null ? g.getUseGlobalDataSourceStat() : this.useGlobalDataSourceStat;
if (useGlobalDataSourceStat != null && useGlobalDataSourceStat.equals(Boolean.TRUE)) {
properties.setProperty(USE_GLOBAL_DATA_SOURCE_STAT, "true");
}
Boolean asyncInit = this.asyncInit == null ? g.getAsyncInit() : this.asyncInit;
if (asyncInit != null && asyncInit.equals(Boolean.TRUE)) {
properties.setProperty(ASYNC_INIT, "true");
}
//filters单独处理默认了stat,wall
String filters = this.filters == null ? g.getFilters() : this.filters;
if (filters == null) {
filters = "stat,wall";
}
if (publicKey != null && publicKey.length() > 0 && !filters.contains("config")) {
filters += ",config";
}
properties.setProperty(FILTERS, filters);
Boolean clearFiltersEnable = this.clearFiltersEnable == null ? g.getClearFiltersEnable() : this.clearFiltersEnable;
if (clearFiltersEnable != null && clearFiltersEnable.equals(Boolean.FALSE)) {
properties.setProperty(CLEAR_FILTERS_ENABLE, "false");
}
Boolean resetStatEnable = this.resetStatEnable == null ? g.getResetStatEnable() : this.resetStatEnable;
if (resetStatEnable != null && resetStatEnable.equals(Boolean.FALSE)) {
properties.setProperty(RESET_STAT_ENABLE, "false");
}
Integer notFullTimeoutRetryCount =
this.notFullTimeoutRetryCount == null ? g.getNotFullTimeoutRetryCount() : this.notFullTimeoutRetryCount;
if (notFullTimeoutRetryCount != null && !notFullTimeoutRetryCount.equals(0)) {
properties.setProperty(NOT_FULL_TIMEOUT_RETRY_COUNT, String.valueOf(notFullTimeoutRetryCount));
}
Integer maxWaitThreadCount = this.maxWaitThreadCount == null ? g.getMaxWaitThreadCount() : this.maxWaitThreadCount;
if (maxWaitThreadCount != null && !maxWaitThreadCount.equals(-1)) {
properties.setProperty(MAX_WAIT_THREAD_COUNT, String.valueOf(maxWaitThreadCount));
}
Boolean failFast = this.failFast == null ? g.getFailFast() : this.failFast;
if (failFast != null && failFast.equals(Boolean.TRUE)) {
properties.setProperty(FAIL_FAST, "true");
}
Long phyTimeoutMillis = this.phyTimeoutMillis == null ? g.getPhyTimeoutMillis() : this.phyTimeoutMillis;
if (phyTimeoutMillis != null && !phyTimeoutMillis.equals(DEFAULT_PHY_TIMEOUT_MILLIS)) {
properties.setProperty(PHY_TIMEOUT_MILLIS, String.valueOf(phyTimeoutMillis));
}
Boolean keepAlive = this.keepAlive == null ? g.getKeepAlive() : this.keepAlive;
if (keepAlive != null && keepAlive.equals(Boolean.TRUE)) {
properties.setProperty(KEEP_ALIVE, "true");
}
Boolean poolPreparedStatements = this.poolPreparedStatements == null ? g.getPoolPreparedStatements() : this.poolPreparedStatements;
if (poolPreparedStatements != null && poolPreparedStatements.equals(Boolean.TRUE)) {
properties.setProperty(POOL_PREPARED_STATEMENTS, "true");
}
Boolean initVariants = this.initVariants == null ? g.getInitVariants() : this.initVariants;
if (initVariants != null && initVariants.equals(Boolean.TRUE)) {
properties.setProperty(INIT_VARIANTS, "true");
}
Boolean initGlobalVariants = this.initGlobalVariants == null ? g.getInitGlobalVariants() : this.initGlobalVariants;
if (initGlobalVariants != null && initGlobalVariants.equals(Boolean.TRUE)) {
properties.setProperty(INIT_GLOBAL_VARIANTS, "true");
}
Boolean useUnfairLock = this.useUnfairLock == null ? g.getUseUnfairLock() : this.useUnfairLock;
if (useUnfairLock != null) {
properties.setProperty(USE_UNFAIR_LOCK, String.valueOf(useUnfairLock));
}
Boolean killWhenSocketReadTimeout =
this.killWhenSocketReadTimeout == null ? g.getKillWhenSocketReadTimeout() : this.killWhenSocketReadTimeout;
if (killWhenSocketReadTimeout != null && killWhenSocketReadTimeout.equals(Boolean.TRUE)) {
properties.setProperty(KILL_WHEN_SOCKET_READ_TIMEOUT, "true");
}
Properties connectProperties = connectionProperties == null ? g.getConnectionProperties() : connectionProperties;
if (publicKey != null && publicKey.length() > 0) {
if (connectProperties == null) {
connectProperties = new Properties();
}
log.info("dynamic-datasource detect druid publicKey,It is highly recommended that you use the built-in encryption method");
connectProperties.setProperty("config.decrypt", "true");
connectProperties.setProperty("config.decrypt.key", publicKey);
}
this.connectionProperties = connectProperties;
Integer maxPoolPreparedStatementPerConnectionSize =
this.maxPoolPreparedStatementPerConnectionSize == null ? g.getMaxPoolPreparedStatementPerConnectionSize()
: this.maxPoolPreparedStatementPerConnectionSize;
if (maxPoolPreparedStatementPerConnectionSize != null && !maxPoolPreparedStatementPerConnectionSize.equals(10)) {
properties.setProperty(MAX_POOL_PREPARED_STATEMENT_PER_CONNECTION_SIZE, String.valueOf(maxPoolPreparedStatementPerConnectionSize));
}
String initConnectionSqls = this.initConnectionSqls == null ? g.getInitConnectionSqls() : this.initConnectionSqls;
if (initConnectionSqls != null && initConnectionSqls.length() > 0) {
properties.setProperty(INIT_CONNECTION_SQLS, initConnectionSqls);
}
//stat配置参数
Integer statSqlMaxSize = this.statSqlMaxSize == null ? g.getStatSqlMaxSize() : this.statSqlMaxSize;
if (statSqlMaxSize != null) {
properties.setProperty(STAT_SQL_MAX_SIZE, String.valueOf(statSqlMaxSize));
}
Boolean logSlowSql = stat.getLogSlowSql() == null ? g.stat.getLogSlowSql() : stat.getLogSlowSql();
if (logSlowSql != null && logSlowSql) {
properties.setProperty(STAT_LOG_SLOW_SQL, "true");
}
Long slowSqlMillis = stat.getSlowSqlMillis() == null ? g.stat.getSlowSqlMillis() : stat.getSlowSqlMillis();
if (slowSqlMillis != null) {
properties.setProperty(STAT_SLOW_SQL_MILLIS, slowSqlMillis.toString());
}
Boolean mergeSql = stat.getMergeSql() == null ? g.stat.getMergeSql() : stat.getMergeSql();
if (mergeSql != null && mergeSql) {
properties.setProperty(STAT_MERGE_SQL, "true");
}
return properties;
} }
Integer maxActive = this.maxActive == null ? g.getMaxActive() : this.maxActive; public List<String> getProxyFilters() {
if (maxActive != null && !maxActive.equals(DEFAULT_MAX_WAIT)) { return proxyFilters;
properties.setProperty(MAX_ACTIVE, String.valueOf(maxActive));
} }
Integer minIdle = this.minIdle == null ? g.getMinIdle() : this.minIdle; public void setProxyFilters(List<String> proxyFilters) {
if (minIdle != null && !minIdle.equals(DEFAULT_MIN_IDLE)) { this.proxyFilters = proxyFilters;
properties.setProperty(MIN_IDLE, String.valueOf(minIdle));
} }
Integer maxWait = this.maxWait == null ? g.getMaxWait() : this.maxWait;
if (maxWait != null && !maxWait.equals(DEFAULT_MAX_WAIT)) {
properties.setProperty(MAX_WAIT, String.valueOf(maxWait));
}
Long timeBetweenEvictionRunsMillis =
this.timeBetweenEvictionRunsMillis == null ? g.getTimeBetweenEvictionRunsMillis() : this.timeBetweenEvictionRunsMillis;
if (timeBetweenEvictionRunsMillis != null && !timeBetweenEvictionRunsMillis.equals(DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS)) {
properties.setProperty(TIME_BETWEEN_EVICTION_RUNS_MILLIS, String.valueOf(timeBetweenEvictionRunsMillis));
}
Long timeBetweenLogStatsMillis =
this.timeBetweenLogStatsMillis == null ? g.getTimeBetweenLogStatsMillis() : this.timeBetweenLogStatsMillis;
if (timeBetweenLogStatsMillis != null && timeBetweenLogStatsMillis > 0) {
properties.setProperty(TIME_BETWEEN_LOG_STATS_MILLIS, String.valueOf(timeBetweenLogStatsMillis));
}
Long minEvictableIdleTimeMillis =
this.minEvictableIdleTimeMillis == null ? g.getMinEvictableIdleTimeMillis() : this.minEvictableIdleTimeMillis;
if (minEvictableIdleTimeMillis != null && !minEvictableIdleTimeMillis.equals(DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS)) {
properties.setProperty(MIN_EVICTABLE_IDLE_TIME_MILLIS, String.valueOf(minEvictableIdleTimeMillis));
}
Long maxEvictableIdleTimeMillis =
this.maxEvictableIdleTimeMillis == null ? g.getMaxEvictableIdleTimeMillis() : this.maxEvictableIdleTimeMillis;
if (maxEvictableIdleTimeMillis != null && !maxEvictableIdleTimeMillis.equals(DEFAULT_MAX_EVICTABLE_IDLE_TIME_MILLIS)) {
properties.setProperty(MAX_EVICTABLE_IDLE_TIME_MILLIS, String.valueOf(maxEvictableIdleTimeMillis));
}
Boolean testWhileIdle = this.testWhileIdle == null ? g.getTestWhileIdle() : this.testWhileIdle;
if (testWhileIdle != null && !testWhileIdle.equals(DEFAULT_WHILE_IDLE)) {
properties.setProperty(TEST_WHILE_IDLE, "false");
}
Boolean testOnBorrow = this.testOnBorrow == null ? g.getTestOnBorrow() : this.testOnBorrow;
if (testOnBorrow != null && !testOnBorrow.equals(DEFAULT_TEST_ON_BORROW)) {
properties.setProperty(TEST_ON_BORROW, "true");
}
String validationQuery = this.validationQuery == null ? g.getValidationQuery() : this.validationQuery;
if (validationQuery != null && validationQuery.length() > 0) {
properties.setProperty(VALIDATION_QUERY, validationQuery);
}
Boolean useGlobalDataSourceStat = this.useGlobalDataSourceStat == null ? g.getUseGlobalDataSourceStat() : this.useGlobalDataSourceStat;
if (useGlobalDataSourceStat != null && useGlobalDataSourceStat.equals(Boolean.TRUE)) {
properties.setProperty(USE_GLOBAL_DATA_SOURCE_STAT, "true");
}
Boolean asyncInit = this.asyncInit == null ? g.getAsyncInit() : this.asyncInit;
if (asyncInit != null && asyncInit.equals(Boolean.TRUE)) {
properties.setProperty(ASYNC_INIT, "true");
}
//filters单独处理默认了stat,wall
String filters = this.filters == null ? g.getFilters() : this.filters;
if (filters == null) {
filters = "stat,wall";
}
if (publicKey != null && publicKey.length() > 0 && !filters.contains("config")) {
filters += ",config";
}
properties.setProperty(FILTERS, filters);
Boolean clearFiltersEnable = this.clearFiltersEnable == null ? g.getClearFiltersEnable() : this.clearFiltersEnable;
if (clearFiltersEnable != null && clearFiltersEnable.equals(Boolean.FALSE)) {
properties.setProperty(CLEAR_FILTERS_ENABLE, "false");
}
Boolean resetStatEnable = this.resetStatEnable == null ? g.getResetStatEnable() : this.resetStatEnable;
if (resetStatEnable != null && resetStatEnable.equals(Boolean.FALSE)) {
properties.setProperty(RESET_STAT_ENABLE, "false");
}
Integer notFullTimeoutRetryCount =
this.notFullTimeoutRetryCount == null ? g.getNotFullTimeoutRetryCount() : this.notFullTimeoutRetryCount;
if (notFullTimeoutRetryCount != null && !notFullTimeoutRetryCount.equals(0)) {
properties.setProperty(NOT_FULL_TIMEOUT_RETRY_COUNT, String.valueOf(notFullTimeoutRetryCount));
}
Integer maxWaitThreadCount = this.maxWaitThreadCount == null ? g.getMaxWaitThreadCount() : this.maxWaitThreadCount;
if (maxWaitThreadCount != null && !maxWaitThreadCount.equals(-1)) {
properties.setProperty(MAX_WAIT_THREAD_COUNT, String.valueOf(maxWaitThreadCount));
}
Boolean failFast = this.failFast == null ? g.getFailFast() : this.failFast;
if (failFast != null && failFast.equals(Boolean.TRUE)) {
properties.setProperty(FAIL_FAST, "true");
}
Long phyTimeoutMillis = this.phyTimeoutMillis == null ? g.getPhyTimeoutMillis() : this.phyTimeoutMillis;
if (phyTimeoutMillis != null && !phyTimeoutMillis.equals(DEFAULT_PHY_TIMEOUT_MILLIS)) {
properties.setProperty(PHY_TIMEOUT_MILLIS, String.valueOf(phyTimeoutMillis));
}
Boolean keepAlive = this.keepAlive == null ? g.getKeepAlive() : this.keepAlive;
if (keepAlive != null && keepAlive.equals(Boolean.TRUE)) {
properties.setProperty(KEEP_ALIVE, "true");
}
Boolean poolPreparedStatements = this.poolPreparedStatements == null ? g.getPoolPreparedStatements() : this.poolPreparedStatements;
if (poolPreparedStatements != null && poolPreparedStatements.equals(Boolean.TRUE)) {
properties.setProperty(POOL_PREPARED_STATEMENTS, "true");
}
Boolean initVariants = this.initVariants == null ? g.getInitVariants() : this.initVariants;
if (initVariants != null && initVariants.equals(Boolean.TRUE)) {
properties.setProperty(INIT_VARIANTS, "true");
}
Boolean initGlobalVariants = this.initGlobalVariants == null ? g.getInitGlobalVariants() : this.initGlobalVariants;
if (initGlobalVariants != null && initGlobalVariants.equals(Boolean.TRUE)) {
properties.setProperty(INIT_GLOBAL_VARIANTS, "true");
}
Boolean useUnfairLock = this.useUnfairLock == null ? g.getUseUnfairLock() : this.useUnfairLock;
if (useUnfairLock != null) {
properties.setProperty(USE_UNFAIR_LOCK, String.valueOf(useUnfairLock));
}
Boolean killWhenSocketReadTimeout =
this.killWhenSocketReadTimeout == null ? g.getKillWhenSocketReadTimeout() : this.killWhenSocketReadTimeout;
if (killWhenSocketReadTimeout != null && killWhenSocketReadTimeout.equals(Boolean.TRUE)) {
properties.setProperty(KILL_WHEN_SOCKET_READ_TIMEOUT, "true");
}
Properties connectProperties = connectionProperties == null ? g.getConnectionProperties() : connectionProperties;
if (publicKey != null && publicKey.length() > 0) {
if (connectProperties == null) {
connectProperties = new Properties();
}
log.info("dynamic-datasource detect druid publicKey,It is highly recommended that you use the built-in encryption method");
connectProperties.setProperty("config.decrypt", "true");
connectProperties.setProperty("config.decrypt.key", publicKey);
}
this.connectionProperties = connectProperties;
Integer maxPoolPreparedStatementPerConnectionSize =
this.maxPoolPreparedStatementPerConnectionSize == null ? g.getMaxPoolPreparedStatementPerConnectionSize()
: this.maxPoolPreparedStatementPerConnectionSize;
if (maxPoolPreparedStatementPerConnectionSize != null && !maxPoolPreparedStatementPerConnectionSize.equals(10)) {
properties.setProperty(MAX_POOL_PREPARED_STATEMENT_PER_CONNECTION_SIZE, String.valueOf(maxPoolPreparedStatementPerConnectionSize));
}
String initConnectionSqls = this.initConnectionSqls == null ? g.getInitConnectionSqls() : this.initConnectionSqls;
if (initConnectionSqls != null && initConnectionSqls.length() > 0) {
properties.setProperty(INIT_CONNECTION_SQLS, initConnectionSqls);
}
//stat配置参数
Integer statSqlMaxSize = this.statSqlMaxSize == null ? g.getStatSqlMaxSize() : this.statSqlMaxSize;
if (statSqlMaxSize != null) {
properties.setProperty(STAT_SQL_MAX_SIZE, String.valueOf(statSqlMaxSize));
}
Boolean logSlowSql = stat.getLogSlowSql() == null ? g.stat.getLogSlowSql() : stat.getLogSlowSql();
if (logSlowSql != null && logSlowSql) {
properties.setProperty(STAT_LOG_SLOW_SQL, "true");
}
Long slowSqlMillis = stat.getSlowSqlMillis() == null ? g.stat.getSlowSqlMillis() : stat.getSlowSqlMillis();
if (slowSqlMillis != null) {
properties.setProperty(STAT_SLOW_SQL_MILLIS, slowSqlMillis.toString());
}
Boolean mergeSql = stat.getMergeSql() == null ? g.stat.getMergeSql() : stat.getMergeSql();
if (mergeSql != null && mergeSql) {
properties.setProperty(STAT_MERGE_SQL, "true");
}
return properties;
}
public List<String> getProxyFilters() {
return proxyFilters;
}
public void setProxyFilters(List<String> proxyFilters) {
this.proxyFilters = proxyFilters;
}
} }

Some files were not shown because too many files have changed in this diff Show More