├── pom.xml └── src ├── main ├── java │ └── com │ │ └── example │ │ └── demo │ │ ├── ShardingJavaDemoApplication.java │ │ ├── common │ │ ├── base │ │ │ ├── BaseRest.java │ │ │ ├── CodeEnumInterface.java │ │ │ └── Result.java │ │ └── utils │ │ │ └── UUIDUtil.java │ │ ├── config │ │ ├── datasource │ │ │ └── DataSourceProperties.java │ │ ├── druidConfig │ │ │ └── DruidAutoConfiguration.java │ │ ├── mybatisplus │ │ │ └── MybatisPlusConfig.java │ │ ├── redis │ │ │ ├── RedisConfig.java │ │ │ ├── RedisPrefixEnum.java │ │ │ └── RedisService.java │ │ └── shardingconfig │ │ │ ├── CarParkShardingTableAlgorithm.java │ │ │ ├── DatasourceEnum.java │ │ │ ├── LocalRegistryCenter.java │ │ │ ├── ShardingRuleConfig.java │ │ │ ├── ShardingService.java │ │ │ └── ShardingTableEnum.java │ │ ├── dao │ │ ├── CarParkMapper.java │ │ ├── OrderMapper.java │ │ └── OrderMapper.xml │ │ ├── pojo │ │ ├── CarPark.java │ │ └── Order.java │ │ ├── rest │ │ ├── CarParkRest.java │ │ └── OrderRest.java │ │ └── service │ │ ├── CarParkService.java │ │ ├── OrderService.java │ │ └── impl │ │ ├── CarParkServiceImpl.java │ │ └── OrderServiceImpl.java └── resources │ ├── META-INF │ └── services │ │ └── org.apache.shardingsphere.orchestration.reg.api.RegistryCenter │ └── application.yml └── test └── java └── com └── example └── demo └── ShardingJavaDemoApplicationTests.java /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.6.RELEASE 9 | 10 | 11 | com.example 12 | demo 13 | 0.0.1-SNAPSHOT 14 | shardingJavaDemo 15 | Demo project for Spring Boot 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-web 25 | 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-test 30 | test 31 | 32 | 33 | org.junit.vintage 34 | junit-vintage-engine 35 | 36 | 37 | 38 | 39 | 40 | org.springframework.boot 41 | spring-boot-starter-data-redis 42 | 43 | 44 | 45 | 46 | com.baomidou 47 | mybatis-plus-boot-starter 48 | 3.3.1.tmp 49 | 50 | 51 | 52 | 53 | org.projectlombok 54 | lombok 55 | provided 56 | 57 | 58 | 59 | 60 | com.alibaba 61 | fastjson 62 | 1.2.60 63 | 64 | 65 | 66 | 67 | mysql 68 | mysql-connector-java 69 | 5.1.44 70 | 71 | 72 | 73 | 74 | com.alibaba 75 | druid 76 | 1.1.20 77 | 78 | 79 | 80 | org.springframework.boot 81 | spring-boot-starter-log4j2 82 | 83 | 84 | 85 | org.apache.shardingsphere 86 | sharding-jdbc-core 87 | 4.0.0 88 | 89 | 90 | 91 | org.apache.shardingsphere 92 | sharding-jdbc-orchestration 93 | 4.0.0 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | org.springframework.boot 102 | spring-boot-maven-plugin 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/ShardingJavaDemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import org.mybatis.spring.annotation.MapperScan; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.context.annotation.ComponentScan; 8 | 9 | @SpringBootApplication 10 | @MapperScan(basePackages = {"com.example.demo.dao"}) 11 | @EnableAutoConfiguration 12 | @ComponentScan(value = {"com.example.demo.config.**","com.example"}) 13 | public class ShardingJavaDemoApplication { 14 | 15 | public static void main(String[] args) { 16 | SpringApplication.run(ShardingJavaDemoApplication.class, args); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/common/base/BaseRest.java: -------------------------------------------------------------------------------- 1 | // 2 | // Source code recreated from a .class file by IntelliJ IDEA 3 | // (powered by Fernflower decompiler) 4 | // 5 | 6 | package com.example.demo.common.base; 7 | 8 | import com.example.demo.common.base.CodeEnumInterface.CodeEnumEnum; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | 11 | import javax.servlet.http.HttpServletRequest; 12 | import java.util.*; 13 | 14 | public class BaseRest { 15 | @Autowired 16 | protected HttpServletRequest request; 17 | private static final String ERROR_MESSAGE = "操作失败"; 18 | public static final String SUCCESS_MESSAGE = "操作成功"; 19 | 20 | public BaseRest() { 21 | } 22 | 23 | public Result addSucResult() { 24 | return this.addResult(true, CodeEnumEnum.SUCCESS.getValue(), "操作成功", (Object)null); 25 | } 26 | 27 | public Result addSucResult(T object) { 28 | if (!(object instanceof List) && !(object instanceof Set) && !(object instanceof LinkedList)) { 29 | return this.addResult(true, CodeEnumEnum.SUCCESS.getValue(), "操作成功", object); 30 | } else { 31 | Map map = new HashMap(); 32 | map.put("list", object); 33 | return this.addResult(true, CodeEnumEnum.SUCCESS.getValue(), "操作成功", map); 34 | } 35 | } 36 | 37 | public Result addSucResult(String message, T object) { 38 | if (!(object instanceof List) && !(object instanceof Set) && !(object instanceof LinkedList)) { 39 | return this.addResult(true, CodeEnumEnum.SUCCESS.getValue(), message, object); 40 | } else { 41 | Map map = new HashMap(); 42 | map.put("list", object); 43 | return this.addResult(true, CodeEnumEnum.SUCCESS.getValue(), message, map); 44 | } 45 | } 46 | 47 | public Result addSucResult(String code, String message, T object) { 48 | if (!(object instanceof List) && !(object instanceof Set) && !(object instanceof LinkedList)) { 49 | return this.addResult(true, code, message, object); 50 | } else { 51 | Map map = new HashMap(); 52 | map.put("list", object); 53 | return this.addResult(true, code, message, map); 54 | } 55 | } 56 | 57 | public Result addSucResult(String message) { 58 | return this.addResult(true, CodeEnumEnum.SUCCESS.getValue(), message, (Object)null); 59 | } 60 | 61 | public Result addErrResult() { 62 | return this.addResult(false, CodeEnumEnum.ERROR.getValue(), "操作失败", (Object)null); 63 | } 64 | 65 | public Result addErrResult(String errMsg) { 66 | return this.addResult(false, CodeEnumEnum.ERROR.getValue(), errMsg, (Object)null); 67 | } 68 | 69 | public Result addErrResult(String code, String errMsg) { 70 | return this.addResult(false, code, errMsg, (Object)null); 71 | } 72 | 73 | public Result addResult(boolean result, String code, String message, T data) { 74 | Result rs = new Result(); 75 | rs.setResult(result); 76 | rs.setCode(code); 77 | rs.setMessage(message); 78 | rs.setData(data); 79 | return rs; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/common/base/CodeEnumInterface.java: -------------------------------------------------------------------------------- 1 | // 2 | // Source code recreated from a .class file by IntelliJ IDEA 3 | // (powered by Fernflower decompiler) 4 | // 5 | 6 | package com.example.demo.common.base; 7 | 8 | public interface CodeEnumInterface { 9 | public static enum CodeEnumEnum implements CodeEnumInterface { 10 | SUCCESS("200", "操作成功."), 11 | LOGIN_WITHOUT("401", "未登录."), 12 | LOGIN_TIMEOUT("40101", "登录超时."), 13 | LOGIN_CONFLICT("40102", "登录冲突."), 14 | PERMISSION_WITHOUT("403", "无权限."), 15 | ERROR("500", "系统未知错误."), 16 | ERROR_INPUT_CHECK("500001", "参数验证错误."), 17 | ERROR_USER_INSERT("5001001", "用户新增异常"), 18 | ERROR_USER_UPDATE("5001002", "用户更新异常"), 19 | ERROR_USER_DELETE("5001003", "用户删除异常"), 20 | ERROR_USER_EXPECTED("5001004", "用户数据不符合预期"), 21 | ERROR_USER_SELECT("5001005", "用户数据未找到"), 22 | ERROR_ROLE_INSERT("5002001", "角色新增异常"), 23 | ERROR_ROLE_UPDATE("5002002", "角色更新异常"), 24 | ERROR_ROLE_DELETE("5002003", "角色删除异常"), 25 | ERROR_ROLE_EXPECTED("5002004", "角色数据不符合预期"), 26 | ERROR_ROLE_SELECT("5002005", "角色数据未找到"), 27 | ERROR_ORG_INSERT("5003001", "组织机构新增异常"), 28 | ERROR_ORG_UPDATE("5003002", "组织机构更新异常"), 29 | ERROR_ORG_DELETE("5003003", "组织机构删除异常"), 30 | ERROR_ORG_EXPECTED("5003004", "组织机构数据不符合预期"), 31 | ERROR_ORG_SELECT("5003005", "组织机构数据未找到"), 32 | ERROR_DIC_INSERT("5004001", "字典新增异常"), 33 | ERROR_DIC_UPDATE("5004002", "字典更新异常"), 34 | ERROR_DIC_DELETE("5004003", "字典删除异常"), 35 | ERROR_DIC_EXPECTED("5004004", "字典数据不符合预期"), 36 | ERROR_DIC_SELECT("5004005", "字典数据未找到"); 37 | 38 | private final String value; 39 | private final String label; 40 | 41 | private CodeEnumEnum(String value, String label) { 42 | this.value = value; 43 | this.label = label; 44 | } 45 | 46 | public String getValue() { 47 | return this.value; 48 | } 49 | 50 | public String getLabel() { 51 | return this.label; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/common/base/Result.java: -------------------------------------------------------------------------------- 1 | // 2 | // Source code recreated from a .class file by IntelliJ IDEA 3 | // (powered by Fernflower decompiler) 4 | // 5 | 6 | package com.example.demo.common.base; 7 | 8 | import java.io.Serializable; 9 | 10 | public class Result implements Serializable { 11 | public static final String SUCCESS_MSG = "操作成功!"; 12 | private static final long serialVersionUID = -34684491868853686L; 13 | private boolean result; 14 | private String code; 15 | private String message; 16 | private String token; 17 | private Long count; 18 | private T data; 19 | 20 | public Result() { 21 | } 22 | 23 | public boolean isResult() { 24 | return this.result; 25 | } 26 | 27 | public void setResult(boolean result) { 28 | this.result = result; 29 | } 30 | 31 | public String getCode() { 32 | return this.code; 33 | } 34 | 35 | public void setCode(String code) { 36 | this.code = code; 37 | } 38 | 39 | public String getMessage() { 40 | return this.message; 41 | } 42 | 43 | public void setMessage(String message) { 44 | this.message = message; 45 | } 46 | 47 | public String getToken() { 48 | return this.token; 49 | } 50 | 51 | public void setToken(String token) { 52 | this.token = token; 53 | } 54 | 55 | public Long getCount() { 56 | return this.count; 57 | } 58 | 59 | public void setCount(Long count) { 60 | this.count = count; 61 | } 62 | 63 | public T getData() { 64 | return this.data; 65 | } 66 | 67 | public void setData(T data) { 68 | this.data = data; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/common/utils/UUIDUtil.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.common.utils; 2 | 3 | import java.util.UUID; 4 | 5 | /** 6 | * @title: UUIDUtil 7 | * @projectName ips-parent 8 | * @description: uuid工具类 9 | * @author zhy 10 | * @date 2020/3/412:17 11 | */ 12 | public class UUIDUtil { 13 | 14 | private UUIDUtil(){} 15 | 16 | /** 17 | * @description: 获取uuid 18 | * @throws 19 | * @return 20 | * @author zhy 21 | * @date 2020/3/4 12:18 22 | */ 23 | public static String getUUID(){ 24 | UUID uuid = UUID.randomUUID(); 25 | return uuid.toString().replaceAll("\\-", ""); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/config/datasource/DataSourceProperties.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.config.datasource; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | import org.springframework.context.annotation.Configuration; 5 | 6 | @Configuration 7 | @ConfigurationProperties(prefix = "spring.druid.datasource") 8 | public class DataSourceProperties { 9 | private String type; 10 | private String driverClassName; 11 | private String url; 12 | private String username; 13 | private String password; 14 | 15 | private Integer initialSize; 16 | private Integer minIdle; 17 | private Integer maxActive; 18 | private Long maxWait; 19 | private Long timeBetweenEvictionRunsMillis; 20 | private Long minEvictableIdleTimeMillis; 21 | private String validationQuery; 22 | private boolean testWhileIdle; 23 | private boolean testOnBorrow; 24 | private boolean testOnReturn; 25 | private boolean poolPreparedStatements; 26 | private Integer maxPoolPreparedStatementPerConnectionSize; 27 | private String filters; 28 | private String connectionProperties; 29 | private boolean useGlobalDataSourceStat; 30 | private String loginUsername; 31 | private String loginPassword; 32 | 33 | public String getType() { 34 | return type; 35 | } 36 | 37 | public void setType(String type) { 38 | this.type = type; 39 | } 40 | 41 | public String getDriverClassName() { 42 | return driverClassName; 43 | } 44 | 45 | public void setDriverClassName(String driverClassName) { 46 | this.driverClassName = driverClassName; 47 | } 48 | 49 | public String getUrl() { 50 | return url; 51 | } 52 | 53 | public void setUrl(String url) { 54 | this.url = url; 55 | } 56 | 57 | public String getUsername() { 58 | return username; 59 | } 60 | 61 | public void setUsername(String username) { 62 | this.username = username; 63 | } 64 | 65 | public String getPassword() { 66 | return password; 67 | } 68 | 69 | public void setPassword(String password) { 70 | this.password = password; 71 | } 72 | 73 | public Integer getInitialSize() { 74 | return initialSize; 75 | } 76 | 77 | public void setInitialSize(Integer initialSize) { 78 | this.initialSize = initialSize; 79 | } 80 | 81 | public Integer getMinIdle() { 82 | return minIdle; 83 | } 84 | 85 | public void setMinIdle(Integer minIdle) { 86 | this.minIdle = minIdle; 87 | } 88 | 89 | public Integer getMaxActive() { 90 | return maxActive; 91 | } 92 | 93 | public void setMaxActive(Integer maxActive) { 94 | this.maxActive = maxActive; 95 | } 96 | 97 | public Long getMaxWait() { 98 | return maxWait; 99 | } 100 | 101 | public void setMaxWait(Long maxWait) { 102 | this.maxWait = maxWait; 103 | } 104 | 105 | public Long getTimeBetweenEvictionRunsMillis() { 106 | return timeBetweenEvictionRunsMillis; 107 | } 108 | 109 | public void setTimeBetweenEvictionRunsMillis(Long timeBetweenEvictionRunsMillis) { 110 | this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; 111 | } 112 | 113 | public Long getMinEvictableIdleTimeMillis() { 114 | return minEvictableIdleTimeMillis; 115 | } 116 | 117 | public void setMinEvictableIdleTimeMillis(Long minEvictableIdleTimeMillis) { 118 | this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; 119 | } 120 | 121 | public String getValidationQuery() { 122 | return validationQuery; 123 | } 124 | 125 | public void setValidationQuery(String validationQuery) { 126 | this.validationQuery = validationQuery; 127 | } 128 | 129 | public boolean isTestWhileIdle() { 130 | return testWhileIdle; 131 | } 132 | 133 | public void setTestWhileIdle(boolean testWhileIdle) { 134 | this.testWhileIdle = testWhileIdle; 135 | } 136 | 137 | public boolean isTestOnBorrow() { 138 | return testOnBorrow; 139 | } 140 | 141 | public void setTestOnBorrow(boolean testOnBorrow) { 142 | this.testOnBorrow = testOnBorrow; 143 | } 144 | 145 | public boolean isTestOnReturn() { 146 | return testOnReturn; 147 | } 148 | 149 | public void setTestOnReturn(boolean testOnReturn) { 150 | this.testOnReturn = testOnReturn; 151 | } 152 | 153 | public boolean isPoolPreparedStatements() { 154 | return poolPreparedStatements; 155 | } 156 | 157 | public void setPoolPreparedStatements(boolean poolPreparedStatements) { 158 | this.poolPreparedStatements = poolPreparedStatements; 159 | } 160 | 161 | public Integer getMaxPoolPreparedStatementPerConnectionSize() { 162 | return maxPoolPreparedStatementPerConnectionSize; 163 | } 164 | 165 | public void setMaxPoolPreparedStatementPerConnectionSize(Integer maxPoolPreparedStatementPerConnectionSize) { 166 | this.maxPoolPreparedStatementPerConnectionSize = maxPoolPreparedStatementPerConnectionSize; 167 | } 168 | 169 | public String getFilters() { 170 | return filters; 171 | } 172 | 173 | public void setFilters(String filters) { 174 | this.filters = filters; 175 | } 176 | 177 | public String getConnectionProperties() { 178 | return connectionProperties; 179 | } 180 | 181 | public void setConnectionProperties(String connectionProperties) { 182 | this.connectionProperties = connectionProperties; 183 | } 184 | 185 | public boolean isUseGlobalDataSourceStat() { 186 | return useGlobalDataSourceStat; 187 | } 188 | 189 | public void setUseGlobalDataSourceStat(boolean useGlobalDataSourceStat) { 190 | this.useGlobalDataSourceStat = useGlobalDataSourceStat; 191 | } 192 | 193 | public String getLoginUsername() { 194 | return loginUsername; 195 | } 196 | 197 | public void setLoginUsername(String loginUsername) { 198 | this.loginUsername = loginUsername; 199 | } 200 | 201 | public String getLoginPassword() { 202 | return loginPassword; 203 | } 204 | 205 | public void setLoginPassword(String loginPassword) { 206 | this.loginPassword = loginPassword; 207 | } 208 | } 209 | 210 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/config/druidConfig/DruidAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.config.druidConfig; 2 | 3 | import com.alibaba.druid.support.http.StatViewServlet; 4 | import com.alibaba.druid.support.http.WebStatFilter; 5 | import com.example.demo.config.datasource.DataSourceProperties; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.web.servlet.FilterRegistrationBean; 8 | import org.springframework.boot.web.servlet.ServletRegistrationBean; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Configuration; 11 | 12 | /** 13 | * Created by sjt on 2017/7/24. 14 | */ 15 | @Configuration 16 | public class DruidAutoConfiguration { 17 | 18 | @Autowired 19 | private DataSourceProperties properties; 20 | 21 | 22 | /** 23 | * Druid的Servlet 24 | * 25 | * @return 26 | */ 27 | @Bean 28 | public ServletRegistrationBean druidStatViewServlet() { 29 | ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*"); 30 | 31 | /** 添加初始化参数:initParams */ 32 | /** 白名单,如果不配置或value为空,则允许所有 */ 33 | //servletRegistrationBean.addInitParameter("allow", "127.0.0.1,192.0.0.1"); 34 | /** 黑名单,与白名单存在相同IP时,优先于白名单 */ 35 | //servletRegistrationBean.addInitParameter("deny", "192.0.0.1"); 36 | /** 用户名 */ 37 | servletRegistrationBean.addInitParameter("loginUsername", properties.getLoginUsername()); 38 | /** 密码 */ 39 | servletRegistrationBean.addInitParameter("loginPassword", properties.getLoginPassword()); 40 | /** 禁用页面上的“Reset All”功能 */ 41 | servletRegistrationBean.addInitParameter("resetEnable", "false"); 42 | return servletRegistrationBean; 43 | } 44 | 45 | /** 46 | * Druid拦截器,用于查看Druid监控 47 | * 48 | * @return 49 | */ 50 | @Bean 51 | public FilterRegistrationBean druidStatFilter() { 52 | FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter()); 53 | /** 过滤规则 */ 54 | filterRegistrationBean.addUrlPatterns("/*"); 55 | /** 忽略资源 */ 56 | filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*"); 57 | return filterRegistrationBean; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/config/mybatisplus/MybatisPlusConfig.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.config.mybatisplus; 2 | 3 | import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.transaction.annotation.EnableTransactionManagement; 7 | 8 | @EnableTransactionManagement 9 | @Configuration 10 | public class MybatisPlusConfig { 11 | 12 | @Bean 13 | public PaginationInterceptor paginationInterceptor() { 14 | PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); 15 | // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false 16 | // paginationInterceptor.setOverflow(false); 17 | // 设置最大单页限制数量,默认 500 条,-1 不受限制 18 | paginationInterceptor.setLimit(-1); 19 | return paginationInterceptor; 20 | } 21 | } -------------------------------------------------------------------------------- /src/main/java/com/example/demo/config/redis/RedisConfig.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.config.redis; 2 | import com.fasterxml.jackson.annotation.JsonAutoDetect; 3 | import com.fasterxml.jackson.annotation.PropertyAccessor; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import org.springframework.cache.CacheManager; 6 | import org.springframework.cache.annotation.CachingConfigurerSupport; 7 | import org.springframework.cache.annotation.EnableCaching; 8 | import org.springframework.cache.interceptor.KeyGenerator; 9 | import org.springframework.cache.interceptor.SimpleKeyGenerator; 10 | import org.springframework.context.annotation.Bean; 11 | import org.springframework.context.annotation.Configuration; 12 | import org.springframework.data.redis.cache.RedisCacheConfiguration; 13 | import org.springframework.data.redis.cache.RedisCacheManager; 14 | import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; 15 | import org.springframework.data.redis.core.RedisTemplate; 16 | import org.springframework.data.redis.core.StringRedisTemplate; 17 | import org.springframework.data.redis.serializer.*; 18 | import java.lang.reflect.Method; 19 | import java.time.Duration; 20 | import java.util.HashMap; 21 | import java.util.HashSet; 22 | import java.util.Map; 23 | import java.util.Set; 24 | /** 25 | * 26 | * @description: redis 缓存配置类 27 | * @create: 2018-05-02 15:14 28 | **/ 29 | @Configuration 30 | @EnableCaching 31 | @SuppressWarnings({"rawtypes","unchecked"}) 32 | public class RedisConfig extends CachingConfigurerSupport { 33 | /** 34 | * json序列化 35 | * @return 36 | */ 37 | @Bean 38 | public RedisSerializer jackson2JsonRedisSerializer() { 39 | //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值 40 | Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class); 41 | ObjectMapper mapper = new ObjectMapper(); 42 | mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); 43 | mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); 44 | serializer.setObjectMapper(mapper); 45 | return serializer; 46 | } 47 | @Bean 48 | public RedisTemplate redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) { 49 | //StringRedisTemplate的构造方法中默认设置了stringSerializer 50 | RedisTemplate template = new RedisTemplate<>(); 51 | //set key serializer 52 | StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); 53 | template.setKeySerializer(stringRedisSerializer); 54 | template.setHashKeySerializer(stringRedisSerializer); 55 | //set value serializer 56 | template.setDefaultSerializer(jackson2JsonRedisSerializer()); 57 | template.setConnectionFactory(lettuceConnectionFactory); 58 | template.afterPropertiesSet(); 59 | return template; 60 | } 61 | @Bean 62 | public StringRedisTemplate stringRedisTemplate(LettuceConnectionFactory lettuceConnectionFactory) { 63 | StringRedisTemplate template = new StringRedisTemplate(); 64 | template.setConnectionFactory(lettuceConnectionFactory); 65 | return template; 66 | } 67 | /** 68 | * 在使用@Cacheable时,如果不指定key,则使用找个默认的key生成器生成的key 69 | * 70 | */ 71 | @Override 72 | @Bean 73 | public KeyGenerator keyGenerator() { 74 | return new SimpleKeyGenerator() { 75 | @Override 76 | public Object generate(Object target, Method method, Object... params) { 77 | StringBuilder sb = new StringBuilder(); 78 | sb.append(target.getClass().getName()); 79 | sb.append(".").append(method.getName()); 80 | StringBuilder paramsSb = new StringBuilder(); 81 | for (Object param : params) { 82 | // 如果不指定,默认生成包含到键值中 83 | if (param != null) { 84 | paramsSb.append(param.toString()); 85 | } 86 | } 87 | if (paramsSb.length() > 0) { 88 | sb.append("_").append(paramsSb); 89 | } 90 | return sb.toString(); 91 | } 92 | }; 93 | } 94 | /** 95 | * 管理缓存 96 | * 97 | * @param lettuceConnectionFactory 98 | * @return 99 | */ 100 | //缓存管理器 101 | @Bean 102 | public CacheManager cacheManager(LettuceConnectionFactory lettuceConnectionFactory) { 103 | // 生成一个默认配置,通过config对象即可对缓存进行自定义配置 104 | RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig(); 105 | // 设置缓存的默认过期时间,也是使用Duration设置 106 | config = config.entryTtl(Duration.ofMinutes(1)) 107 | // 设置 key为string序列化 108 | .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())) 109 | // 设置value为json序列化 110 | .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer() )) 111 | // 不缓存空值 112 | .disableCachingNullValues(); 113 | // 设置一个初始化的缓存空间set集合 114 | Set cacheNames = new HashSet<>(); 115 | cacheNames.add("company_goods_info"); 116 | // 对每个缓存空间应用不同的配置 117 | Map configMap = new HashMap<>(); 118 | configMap.put("company_goods_info", config); 119 | // 使用自定义的缓存配置初始化一个cacheManager 120 | return RedisCacheManager.builder(lettuceConnectionFactory) 121 | // 一定要先调用该方法设置初始化的缓存名,再初始化相关的配置 122 | .initialCacheNames(cacheNames) 123 | .withInitialCacheConfigurations(configMap) 124 | .build(); 125 | } 126 | } -------------------------------------------------------------------------------- /src/main/java/com/example/demo/config/redis/RedisPrefixEnum.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.config.redis; 2 | 3 | /** 4 | * @author 53240 5 | * @date 2019-10-21 18:52 6 | * @desc 7 | */ 8 | public enum RedisPrefixEnum { 9 | 10 | 11 | CAR_PARK_ID_CATALOG("carPark:idCatalog","当前所有的停车场id"), 12 | SHARDING_RULE_ORDER("sharding:rule:order","订单表分表规则纪录"), 13 | ; 14 | private final String value; 15 | private final String desc; 16 | 17 | RedisPrefixEnum(final String value, final String desc) { 18 | this.value = value; 19 | this.desc = desc; 20 | } 21 | 22 | public String getValue() { 23 | return this.value; 24 | } 25 | 26 | public String getDesc() { 27 | return this.desc; 28 | } 29 | 30 | public static String getDescByValue(String value) { 31 | String desc = ""; 32 | RedisPrefixEnum[] var2 = values(); 33 | int var3 = var2.length; 34 | 35 | for(int var4 = 0; var4 < var3; ++var4) { 36 | RedisPrefixEnum o = var2[var4]; 37 | if (o.getValue().equals(value)) { 38 | desc = o.getDesc(); 39 | } 40 | } 41 | 42 | return desc; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/config/redis/RedisService.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.config.redis; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.data.redis.core.RedisTemplate; 5 | import org.springframework.stereotype.Component; 6 | 7 | import java.util.Collection; 8 | import java.util.Date; 9 | import java.util.Set; 10 | import java.util.concurrent.TimeUnit; 11 | import java.util.stream.Collectors; 12 | import java.util.stream.Stream; 13 | 14 | @Component 15 | public class RedisService { 16 | 17 | @Autowired 18 | private RedisTemplate redisTemplate; 19 | 20 | /** 21 | * 默认过期时长,单位:秒 22 | */ 23 | public static final long DEFAULT_EXPIRE = 60 * 60 * 24L; 24 | 25 | /** 26 | * 不设置过期时长 27 | */ 28 | public static final long NOT_EXPIRE = -1; 29 | 30 | 31 | 32 | 33 | public boolean existsKey(String key) { 34 | return redisTemplate.hasKey(key); 35 | } 36 | 37 | /** 38 | * 重名名key,如果newKey已经存在,则newKey的原值被覆盖 39 | * 40 | * @param oldKey 41 | * @param newKey 42 | */ 43 | public void renameKey(String oldKey, String newKey) { 44 | redisTemplate.rename(oldKey, newKey); 45 | } 46 | 47 | /** 48 | * newKey不存在时才重命名 49 | * 50 | * @param oldKey 51 | * @param newKey 52 | * @return 修改成功返回true 53 | */ 54 | public boolean renameKeyNotExist(String oldKey, String newKey) { 55 | return redisTemplate.renameIfAbsent(oldKey, newKey); 56 | } 57 | 58 | /** 59 | * 删除key 60 | * 61 | * @param key 62 | */ 63 | public void deleteKey(String key) { 64 | redisTemplate.delete(key); 65 | } 66 | 67 | /** 68 | * 删除多个key 69 | * 70 | * @param keys 71 | */ 72 | public void deleteKey(String... keys) { 73 | Set kSet = Stream.of(keys).map(k -> k).collect(Collectors.toSet()); 74 | redisTemplate.delete(kSet); 75 | } 76 | 77 | /** 78 | * 删除Key的集合 79 | * 80 | * @param keys 81 | */ 82 | public void deleteKey(Collection keys) { 83 | Set kSet = keys.stream().map(k -> k).collect(Collectors.toSet()); 84 | redisTemplate.delete(kSet); 85 | } 86 | 87 | /** 88 | * 设置key的生命周期 89 | * 90 | * @param key 91 | * @param time 92 | * @param timeUnit 93 | */ 94 | public void expireKey(String key, long time, TimeUnit timeUnit) { 95 | redisTemplate.expire(key, time, timeUnit); 96 | } 97 | 98 | /** 99 | * 指定key在指定的日期过期 100 | * 101 | * @param key 102 | * @param date 103 | */ 104 | public void expireKeyAt(String key, Date date) { 105 | redisTemplate.expireAt(key, date); 106 | } 107 | 108 | /** 109 | * 查询key的生命周期 110 | * 111 | * @param key 112 | * @param timeUnit 113 | * @return 114 | */ 115 | public long getKeyExpire(String key, TimeUnit timeUnit) { 116 | return redisTemplate.getExpire(key, timeUnit); 117 | } 118 | 119 | /** 120 | * 将key设置为永久有效 121 | * 122 | * @param key 123 | */ 124 | public void persistKey(String key) { 125 | redisTemplate.persist(key); 126 | } 127 | } -------------------------------------------------------------------------------- /src/main/java/com/example/demo/config/shardingconfig/CarParkShardingTableAlgorithm.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.config.shardingconfig; 2 | 3 | import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm; 4 | import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue; 5 | 6 | import java.util.Collection; 7 | 8 | /** 9 | * @title: CarParkShardingTableAlgorithm 10 | * @projectName shardingdemo 11 | * @description: 按停车场id分表 12 | * @author zhy 13 | * @date 2020/5/611:25 14 | */ 15 | public class CarParkShardingTableAlgorithm implements PreciseShardingAlgorithm { 16 | 17 | 18 | @Override 19 | public String doSharding(Collection collection, PreciseShardingValue preciseShardingValue) { 20 | StringBuilder sb = new StringBuilder(); 21 | String value = preciseShardingValue.getValue(); 22 | String logicTableName = preciseShardingValue.getLogicTableName(); 23 | sb.append(logicTableName).append("_").append(value); 24 | return sb.toString(); 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/config/shardingconfig/DatasourceEnum.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.config.shardingconfig; 2 | 3 | 4 | public enum DatasourceEnum { 5 | 6 | DEFAULT("ds0", "默认数据源"), 7 | 8 | ; 9 | 10 | 11 | private final String value; 12 | private final String desc; 13 | 14 | DatasourceEnum(final String value, final String desc) { 15 | this.value = value; 16 | this.desc = desc; 17 | } 18 | 19 | public String getValue() { 20 | return this.value; 21 | } 22 | 23 | // Jackson 注解为 JsonValue 返回中文 json 描述 24 | public String getDesc() { 25 | return this.desc; 26 | } 27 | 28 | public static String getDescByValue(String value) { 29 | String desc = ""; 30 | DatasourceEnum[] var2 = values(); 31 | int var3 = var2.length; 32 | 33 | for (int var4 = 0; var4 < var3; ++var4) { 34 | DatasourceEnum o = var2[var4]; 35 | if (o.getValue().equals(value)) { 36 | desc = o.getDesc(); 37 | } 38 | } 39 | 40 | return desc; 41 | } 42 | 43 | /** 44 | * 根据value 获取枚举 45 | * @param value 46 | * @throws 47 | * @return com.cec.park.common.enums.carspaces.ExistEnum 48 | * @author zhy 49 | * @date 2020/4/14 10:07 50 | */ 51 | public static DatasourceEnum getByValue(Integer value) { 52 | for (DatasourceEnum carSpaceTypeEnum : values()) { 53 | if (carSpaceTypeEnum.getValue() .equals(value) ) { 54 | //获取指定的枚举 55 | return carSpaceTypeEnum; 56 | } 57 | } 58 | return DEFAULT; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/config/shardingconfig/LocalRegistryCenter.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.config.shardingconfig; 2 | 3 | import org.apache.shardingsphere.orchestration.reg.api.RegistryCenter; 4 | import org.apache.shardingsphere.orchestration.reg.api.RegistryCenterConfiguration; 5 | import org.apache.shardingsphere.orchestration.reg.listener.DataChangedEventListener; 6 | 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.Properties; 10 | import java.util.concurrent.ConcurrentHashMap; 11 | 12 | public class LocalRegistryCenter implements RegistryCenter { 13 | public static Map listeners = new ConcurrentHashMap<>(); 14 | 15 | private RegistryCenterConfiguration config; 16 | 17 | private Properties properties; 18 | /** 19 | * public 是为了在重置节点的时候减少去重新读配置 20 | */ 21 | public static Map values = new ConcurrentHashMap<>(); 22 | 23 | @Override 24 | public void init(RegistryCenterConfiguration config) { 25 | this.config = config; 26 | } 27 | 28 | @Override 29 | public String get(String key) { 30 | return values.get(key); 31 | } 32 | 33 | @Override 34 | public String getDirectly(String key) { 35 | return values.get(key); 36 | } 37 | 38 | @Override 39 | public boolean isExisted(String key) { 40 | return values.containsKey(key); 41 | } 42 | 43 | @Override 44 | public List getChildrenKeys(String key) { 45 | return null; 46 | } 47 | 48 | @Override 49 | public void persist(String key, String value) { 50 | values.put(key, value); 51 | } 52 | 53 | @Override 54 | public void update(String key, String value) { 55 | values.put(key, value); 56 | } 57 | 58 | @Override 59 | public void persistEphemeral(String key, String value) { 60 | values.put(key, value); 61 | } 62 | 63 | @Override 64 | public void watch(String key, DataChangedEventListener dataChangedEventListener) { 65 | if (null != dataChangedEventListener) { 66 | // 将数据改变的事件监听器缓存下来 67 | listeners.put(key, dataChangedEventListener); 68 | } 69 | } 70 | 71 | @Override 72 | public void close() { 73 | config = null; 74 | } 75 | 76 | @Override 77 | public void initLock(String key) { 78 | 79 | } 80 | 81 | @Override 82 | public boolean tryLock() { 83 | return false; 84 | } 85 | 86 | @Override 87 | public void tryRelease() { 88 | 89 | } 90 | 91 | @Override 92 | public String getType() { 93 | // 【关键点1】,留着文章后续引用 94 | return "shardingLocalRegisterCenter"; 95 | } 96 | 97 | @Override 98 | public Properties getProperties() { 99 | return properties; 100 | } 101 | 102 | @Override 103 | public void setProperties(Properties properties) { 104 | this.properties = properties; 105 | } 106 | } -------------------------------------------------------------------------------- /src/main/java/com/example/demo/config/shardingconfig/ShardingRuleConfig.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.config.shardingconfig; 2 | 3 | import com.alibaba.druid.filter.Filter; 4 | import com.alibaba.druid.filter.logging.Slf4jLogFilter; 5 | import com.alibaba.druid.filter.stat.StatFilter; 6 | import com.alibaba.druid.pool.DruidDataSource; 7 | import com.alibaba.druid.util.StringUtils; 8 | import com.alibaba.druid.wall.WallConfig; 9 | import com.alibaba.druid.wall.WallFilter; 10 | import com.example.demo.config.datasource.DataSourceProperties; 11 | import com.example.demo.config.redis.RedisConfig; 12 | import com.example.demo.config.redis.RedisPrefixEnum; 13 | import org.apache.shardingsphere.api.config.sharding.ShardingRuleConfiguration; 14 | import org.apache.shardingsphere.api.config.sharding.TableRuleConfiguration; 15 | import org.apache.shardingsphere.api.config.sharding.strategy.StandardShardingStrategyConfiguration; 16 | import org.apache.shardingsphere.orchestration.config.OrchestrationConfiguration; 17 | import org.apache.shardingsphere.orchestration.reg.api.RegistryCenterConfiguration; 18 | import org.apache.shardingsphere.shardingjdbc.orchestration.api.OrchestrationShardingDataSourceFactory; 19 | import org.springframework.beans.factory.annotation.Autowired; 20 | import org.springframework.boot.autoconfigure.AutoConfigureAfter; 21 | import org.springframework.context.annotation.Bean; 22 | import org.springframework.context.annotation.Configuration; 23 | import org.springframework.data.redis.core.RedisTemplate; 24 | 25 | import javax.sql.DataSource; 26 | import java.sql.SQLException; 27 | import java.util.*; 28 | 29 | /** 30 | * @title: ShardingRuleConfig 31 | * @projectName shardingJavaDemo 32 | * @description: TODO 33 | * @author zhy 34 | * @date 2020/5/910:23 35 | */ 36 | @Configuration 37 | @AutoConfigureAfter({DataSourceProperties.class, RedisConfig.class}) 38 | public class ShardingRuleConfig { 39 | 40 | private String defaultDataSource = DatasourceEnum.DEFAULT.getValue(); 41 | 42 | @Autowired 43 | private RedisTemplate redisTemplate; 44 | 45 | @Autowired 46 | private DataSourceProperties properties; 47 | 48 | /** 49 | * shardingjdbc数据源 50 | * @param 51 | * @throws 52 | * @return javax.sql.DataSource 53 | * @author zhy 54 | * @date 2020/5/9 10:33 55 | */ 56 | @Bean 57 | public DataSource dataSource() throws SQLException { 58 | // 配置真实数据源 59 | Map dataSourceMap = new HashMap<>(); 60 | //多数据源配置 61 | //数据源1 62 | DruidDataSource dataSource0 = druidDataSource(); 63 | dataSourceMap.put(defaultDataSource, dataSource0); 64 | //数据源2 65 | // DruidDataSource dataSource1 = createDb1(); 66 | // dataSourceMap.put("ds1", dataSource1); 67 | 68 | // 配置分片规则 69 | ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration(); 70 | //订单表分片规则 71 | TableRuleConfiguration orderRuleConfig = orderRuleConfig(); 72 | shardingRuleConfig.getTableRuleConfigs().add(orderRuleConfig); 73 | //可以继续用add添加分片规则 74 | //shardingRuleConfig.getTableRuleConfigs().add(orderRuleConfig); 75 | //多数据源一定要指定默认数据源,只有一个数据源就不需要 76 | //shardingRuleConfig.setDefaultDataSourceName("ds0"); 77 | Properties p = new Properties(); 78 | //打印sql语句,生产环境关闭 79 | p.setProperty("sql.show",Boolean.TRUE.toString()); 80 | OrchestrationConfiguration orchestrationConfig = new OrchestrationConfiguration( 81 | "orchestration-sharding-data-source", new RegistryCenterConfiguration("shardingLocalRegisterCenter"), 82 | false); 83 | return OrchestrationShardingDataSourceFactory.createDataSource(dataSourceMap, shardingRuleConfig, p, 84 | orchestrationConfig); 85 | } 86 | 87 | /** 88 | * 订单分片规则 89 | * @param 90 | * @throws 91 | * @return io.shardingjdbc.core.api.config.TableRuleConfiguration 92 | * @author zhy 93 | * @date 2020/5/7 10:28 94 | */ 95 | private TableRuleConfiguration orderRuleConfig(){ 96 | String logicTable = ShardingTableEnum.ORDER.getValue(); 97 | String orderNodesByRedisCarPark = getActualDataNodesByCatalog(ShardingTableEnum.ORDER); 98 | //t_order_default 这张表是默认表,需要事先建好,防止首次启动报错 99 | String actualDataNodes = StringUtils.isEmpty(orderNodesByRedisCarPark) ? "ds0.t_order_default" : orderNodesByRedisCarPark; 100 | TableRuleConfiguration tableRuleConfig = new TableRuleConfiguration(logicTable,actualDataNodes); 101 | //设置分表策略 102 | tableRuleConfig.setTableShardingStrategyConfig(new StandardShardingStrategyConfiguration("car_park_id",new CarParkShardingTableAlgorithm())); 103 | //根据时间将策略放进redis中,方便读取替换 104 | redisTemplate.opsForZSet().add(RedisPrefixEnum.SHARDING_RULE_ORDER.getValue(),actualDataNodes,new Date().getTime()); 105 | return tableRuleConfig; 106 | } 107 | 108 | 109 | /** 110 | * 根据分表类型获取初始化actualDataNodes 111 | * @param logicTable 112 | * @throws 113 | * @return java.lang.String 114 | * @author zhy 115 | * @date 2020/5/11 14:52 116 | */ 117 | public String getActualDataNodesByCatalog(ShardingTableEnum logicTable){ 118 | String redisKey = RedisPrefixEnum.CAR_PARK_ID_CATALOG.getValue(); 119 | //获取所有的停车场 120 | Set keys = redisTemplate.opsForHash().keys(redisKey); 121 | if (keys.isEmpty()){ 122 | return null; 123 | } 124 | StringBuilder sb = new StringBuilder(); 125 | keys.forEach(obj -> { 126 | sb.append(defaultDataSource).append(".").append(logicTable.getValue()).append("_").append(obj.toString()).append(","); 127 | }); 128 | sb.deleteCharAt(sb.length() - 1); 129 | return sb.toString(); 130 | } 131 | 132 | /** 133 | * 获取druid数据库链接 134 | * @param 135 | * @throws 136 | * @return com.alibaba.druid.pool.DruidDataSource 137 | * @author zhy 138 | * @date 2020/5/7 10:29 139 | */ 140 | private DruidDataSource druidDataSource() { 141 | DruidDataSource dataSource = new DruidDataSource(); 142 | dataSource.setDriverClassName(properties.getDriverClassName()); 143 | dataSource.setUrl(properties.getUrl()); 144 | dataSource.setUsername(properties.getUsername()); 145 | dataSource.setPassword(properties.getPassword()); 146 | dataSource.setInitialSize(properties.getInitialSize()); 147 | dataSource.setMinIdle(properties.getMinIdle()); 148 | dataSource.setMaxActive(properties.getMaxActive()); 149 | dataSource.setMaxWait(properties.getMaxWait()); 150 | dataSource.setTimeBetweenEvictionRunsMillis(properties.getTimeBetweenEvictionRunsMillis()); 151 | dataSource.setMinEvictableIdleTimeMillis(properties.getMinEvictableIdleTimeMillis()); 152 | String validationQuery = properties.getValidationQuery(); 153 | if (validationQuery != null && !"".equals(validationQuery)) { 154 | dataSource.setValidationQuery(validationQuery); 155 | } 156 | dataSource.setTestWhileIdle(properties.isTestWhileIdle()); 157 | dataSource.setTestOnBorrow(properties.isTestOnBorrow()); 158 | dataSource.setTestOnReturn(properties.isTestOnReturn()); 159 | if (properties.isPoolPreparedStatements()) { 160 | dataSource.setMaxPoolPreparedStatementPerConnectionSize(properties.getMaxPoolPreparedStatementPerConnectionSize()); 161 | } 162 | String connectionPropertiesStr = properties.getConnectionProperties(); 163 | if (connectionPropertiesStr != null && !"".equals(connectionPropertiesStr)) { 164 | Properties connectProperties = new Properties(); 165 | String[] propertiesList = connectionPropertiesStr.split(";"); 166 | for (String propertiesTmp : propertiesList) { 167 | String[] obj = propertiesTmp.split("="); 168 | String key = obj[0]; 169 | String value = obj[1]; 170 | connectProperties.put(key, value); 171 | } 172 | dataSource.setConnectProperties(connectProperties); 173 | } 174 | dataSource.setUseGlobalDataSourceStat(properties.isUseGlobalDataSourceStat()); 175 | WallConfig wallConfig = new WallConfig(); 176 | wallConfig.setMultiStatementAllow(true); 177 | WallFilter wallFilter = new WallFilter(); 178 | wallFilter.setConfig(wallConfig); 179 | //打开日志记录过滤器,可通过log4j2,记录sql application.yml中配置【logging:config: classpath:logConfig/log4j2.xml】 180 | Slf4jLogFilter slf4jLogFilter = new Slf4jLogFilter(); 181 | slf4jLogFilter.setStatementCreateAfterLogEnabled(false); 182 | slf4jLogFilter.setStatementCloseAfterLogEnabled(false); 183 | slf4jLogFilter.setResultSetOpenAfterLogEnabled(false); 184 | slf4jLogFilter.setResultSetCloseAfterLogEnabled(false); 185 | List filters = new ArrayList<>(); 186 | filters.add(wallFilter); 187 | filters.add(new StatFilter()); 188 | filters.add(slf4jLogFilter); 189 | 190 | dataSource.setProxyFilters(filters); 191 | return dataSource; 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/config/shardingconfig/ShardingService.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.config.shardingconfig; 2 | 3 | import com.example.demo.config.datasource.DataSourceProperties; 4 | import com.example.demo.config.redis.RedisConfig; 5 | import com.example.demo.config.redis.RedisPrefixEnum; 6 | import org.apache.shardingsphere.orchestration.reg.listener.DataChangedEvent; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.autoconfigure.AutoConfigureAfter; 9 | import org.springframework.data.redis.core.RedisTemplate; 10 | import org.springframework.stereotype.Component; 11 | 12 | import java.util.ArrayList; 13 | import java.util.Set; 14 | 15 | /** 16 | * @title: ShardingService 17 | * @projectName shardingJavaDemo 18 | * @description: TODO 19 | * @author zhy 20 | * @date 2020/5/1115:08 21 | */ 22 | @Component 23 | @AutoConfigureAfter({RedisConfig.class}) 24 | public class ShardingService { 25 | 26 | @Autowired 27 | private RedisTemplate redisTemplate; 28 | 29 | @Autowired 30 | private ShardingRuleConfig shardingRuleConfig; 31 | 32 | /** 33 | * 替换sharding里的分表规则ActualDataNodes的值 34 | * @param oldRule 35 | * @param newRule 36 | * @throws 37 | * @return void 38 | * @author zhy 39 | * @date 2020/5/11 15:12 40 | */ 41 | public void replaceActualDataNodes(String oldRule,String newRule){ 42 | // 获取已有的配置 43 | String rules = LocalRegistryCenter.values 44 | .get("/orchestration-sharding-data-source/config/schema/logic_db/rule"); 45 | // 修改规则 46 | String rule = rules.replace(oldRule, newRule); 47 | LocalRegistryCenter.listeners.get("/orchestration-sharding-data-source/config/schema") 48 | .onChange(new DataChangedEvent( 49 | "/orchestration-sharding-data-source/config/schema/logic_db/rule", 50 | rule, DataChangedEvent.ChangedType.UPDATED)); 51 | LocalRegistryCenter.values.put("/orchestration-sharding-data-source/config/schema/logic_db/rule",rule); 52 | } 53 | 54 | /** 55 | * 获取当前的分表规则 56 | * @param shardingTableEnum 57 | * @throws 58 | * @return java.lang.String 59 | * @author zhy 60 | * @date 2020/5/11 15:56 61 | */ 62 | public String getActualDataNodesInRedis(ShardingTableEnum shardingTableEnum){ 63 | String redisKey = RedisPrefixEnum.SHARDING_RULE_ORDER.getValue(); 64 | //倒序获取一条最新的纪录 65 | Set objects = redisTemplate.opsForZSet().reverseRange(redisKey, 0, 1); 66 | return new ArrayList<>(objects).get(0).toString(); 67 | } 68 | 69 | /** 70 | * 根据redis中存储的停车场id获取分表规则 71 | * @param shardingTableEnum 72 | * @throws 73 | * @return java.lang.String 74 | * @author zhy 75 | * @date 2020/5/11 16:09 76 | */ 77 | public String getActualDataNodesByCatalog(ShardingTableEnum shardingTableEnum){ 78 | return shardingRuleConfig.getActualDataNodesByCatalog(shardingTableEnum); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/config/shardingconfig/ShardingTableEnum.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.config.shardingconfig; 2 | 3 | 4 | /** 5 | * 需要分表的表枚举说明 6 | * @param null 7 | * @throws 8 | * @return 9 | * @author zhy 10 | * @date 2020/5/11 13:21 11 | */ 12 | public enum ShardingTableEnum { 13 | 14 | ORDER("t_order", "订单表"), 15 | 16 | ; 17 | 18 | 19 | private final String value; 20 | private final String desc; 21 | 22 | ShardingTableEnum(final String value, final String desc) { 23 | this.value = value; 24 | this.desc = desc; 25 | } 26 | 27 | public String getValue() { 28 | return this.value; 29 | } 30 | 31 | // Jackson 注解为 JsonValue 返回中文 json 描述 32 | public String getDesc() { 33 | return this.desc; 34 | } 35 | 36 | public static String getDescByValue(String value) { 37 | String desc = ""; 38 | ShardingTableEnum[] var2 = values(); 39 | int var3 = var2.length; 40 | 41 | for (int var4 = 0; var4 < var3; ++var4) { 42 | ShardingTableEnum o = var2[var4]; 43 | if (o.getValue().equals(value)) { 44 | desc = o.getDesc(); 45 | } 46 | } 47 | 48 | return desc; 49 | } 50 | 51 | /** 52 | * 根据value 获取枚举 53 | * @param value 54 | * @throws 55 | * @return com.cec.park.common.enums.carspaces.ExistEnum 56 | * @author zhy 57 | * @date 2020/4/14 10:07 58 | */ 59 | public static ShardingTableEnum getByValue(Integer value) { 60 | for (ShardingTableEnum carSpaceTypeEnum : values()) { 61 | if (carSpaceTypeEnum.getValue() .equals(value) ) { 62 | //获取指定的枚举 63 | return carSpaceTypeEnum; 64 | } 65 | } 66 | return ORDER; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/dao/CarParkMapper.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.dao; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.example.demo.pojo.CarPark; 5 | import org.apache.ibatis.annotations.Mapper; 6 | 7 | /** 8 | * @title: OrderMapper 9 | * @projectName shardingdemo 10 | * @description: TODO 11 | * @author zhy 12 | * @date 2020/5/69:30 13 | */ 14 | @Mapper 15 | public interface CarParkMapper extends BaseMapper { 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/dao/OrderMapper.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.dao; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.example.demo.pojo.Order; 5 | import org.apache.ibatis.annotations.Mapper; 6 | import org.apache.ibatis.annotations.Param; 7 | import org.apache.ibatis.annotations.Update; 8 | 9 | /** 10 | * @title: OrderMapper 11 | * @projectName shardingdemo 12 | * @description: TODO 13 | * @author zhy 14 | * @date 2020/5/69:30 15 | */ 16 | @Mapper 17 | public interface OrderMapper extends BaseMapper { 18 | 19 | /** 20 | * 创建表 21 | * @param tableName 22 | * @throws 23 | * @return void 24 | * @author zhy 25 | * @date 2020/5/11 16:17 26 | */ 27 | @Update(" CREATE TABLE ${tableName} (\n" + 28 | " id varchar(64) NOT NULL,\n" + 29 | " name varchar(100) DEFAULT NULL COMMENT '名称',\n" + 30 | " car_park_id varchar(64) DEFAULT NULL COMMENT '停车场id',\n" + 31 | " no varchar(100) DEFAULT NULL COMMENT '订单号',\n" + 32 | " create_time datetime DEFAULT NULL COMMENT '创建时间',\n" + 33 | " PRIMARY KEY (id)\n" + 34 | " ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='测试分表';") 35 | void createNewTable(@Param("tableName") String tableName); 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/dao/OrderMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/pojo/CarPark.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.pojo; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableId; 4 | import com.baomidou.mybatisplus.annotation.TableName; 5 | import lombok.Data; 6 | 7 | import java.util.Date; 8 | 9 | /** 10 | * @title: CarPark 11 | * @projectName shardingdemo 12 | * @description: TODO 13 | * @author zhy 14 | * @date 2020/5/810:12 15 | */ 16 | @TableName("t_car_park") 17 | @Data 18 | public class CarPark { 19 | 20 | @TableId 21 | private String id; 22 | 23 | private String name; 24 | 25 | private Date createTime; 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/pojo/Order.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.pojo; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableId; 4 | import com.baomidou.mybatisplus.annotation.TableName; 5 | import lombok.Data; 6 | 7 | import java.io.Serializable; 8 | import java.util.Date; 9 | 10 | /** 11 | * @title: Order 12 | * @projectName shardingdemo 13 | * @description: 订单实体 14 | * @author zhy 15 | * @date 2020/5/69:26 16 | */ 17 | @TableName("t_order") 18 | @Data 19 | public class Order implements Serializable { 20 | 21 | // 串行版本ID 22 | private static final long serialVersionUID = 3310565453981832744L; 23 | 24 | @TableId 25 | private String id; 26 | 27 | private String name; 28 | 29 | private String carParkId; 30 | 31 | private String no; 32 | 33 | private Date createTime; 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/rest/CarParkRest.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.rest; 2 | 3 | import com.example.demo.common.base.BaseRest; 4 | import com.example.demo.common.base.Result; 5 | import com.example.demo.common.utils.UUIDUtil; 6 | import com.example.demo.pojo.CarPark; 7 | import com.example.demo.service.CarParkService; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.web.bind.annotation.PostMapping; 10 | import org.springframework.web.bind.annotation.RequestBody; 11 | import org.springframework.web.bind.annotation.RequestMapping; 12 | import org.springframework.web.bind.annotation.RestController; 13 | 14 | import java.util.Date; 15 | 16 | /** 17 | * @title: OrderRest 18 | * @projectName shardingdemo 19 | * @description: TODO 20 | * @author zhy 21 | * @date 2020/5/69:33 22 | */ 23 | @RestController 24 | @RequestMapping("/carPark") 25 | public class CarParkRest extends BaseRest { 26 | 27 | @Autowired 28 | private CarParkService carParkService; 29 | 30 | @PostMapping("/save") 31 | public Result save(@RequestBody CarPark carPark){ 32 | carPark.setId(UUIDUtil.getUUID()); 33 | carPark.setCreateTime(new Date()); 34 | carParkService.save(carPark); 35 | return addSucResult(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/rest/OrderRest.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.rest; 2 | 3 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 4 | import com.baomidou.mybatisplus.core.metadata.IPage; 5 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 6 | import com.example.demo.common.base.BaseRest; 7 | import com.example.demo.common.base.Result; 8 | import com.example.demo.common.utils.UUIDUtil; 9 | import com.example.demo.pojo.Order; 10 | import com.example.demo.service.OrderService; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.web.bind.annotation.*; 13 | 14 | import java.util.Date; 15 | 16 | /** 17 | * @title: OrderRest 18 | * @projectName shardingdemo 19 | * @description: TODO 20 | * @author zhy 21 | * @date 2020/5/69:33 22 | */ 23 | @RestController 24 | @RequestMapping("/order") 25 | public class OrderRest extends BaseRest { 26 | 27 | @Autowired 28 | private OrderService orderService; 29 | 30 | @GetMapping("/{id}") 31 | public Result getById(@PathVariable String id){ 32 | Order order = orderService.getById(id); 33 | return addSucResult(order); 34 | } 35 | 36 | @PostMapping("/{carParkId}") 37 | public Result save(@PathVariable String carParkId){ 38 | Order order = new Order(); 39 | order.setId(UUIDUtil.getUUID()); 40 | order.setCarParkId(carParkId); 41 | order.setNo(order.getId()); 42 | order.setCreateTime(new Date()); 43 | orderService.save(order); 44 | return addSucResult(); 45 | } 46 | 47 | @GetMapping("list/{carParkId}") 48 | public Result list(@PathVariable String carParkId){ 49 | if("all".equals(carParkId)){ 50 | return addSucResult(orderService.list()); 51 | }else{ 52 | LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); 53 | lambdaQueryWrapper.eq(Order::getCarParkId,carParkId); 54 | return addSucResult(orderService.list(lambdaQueryWrapper)); 55 | } 56 | } 57 | 58 | @PostMapping("/listPage/{carParkId}") 59 | public Result listPage(@PathVariable String carParkId){ 60 | Integer pageSize = 10; 61 | Integer pageNum = 1; 62 | IPage page = new Page<>(pageNum, pageSize, true); 63 | if("all".equals(carParkId)){ 64 | return addSucResult(orderService.page(page)); 65 | }else{ 66 | LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); 67 | lambdaQueryWrapper.eq(Order::getCarParkId,carParkId); 68 | return addSucResult(orderService.page(page,lambdaQueryWrapper)); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/service/CarParkService.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.example.demo.pojo.CarPark; 5 | 6 | /** 7 | * @title: OrderService 8 | * @projectName shardingdemo 9 | * @description: TODO 10 | * @author zhy 11 | * @date 2020/5/69:31 12 | */ 13 | public interface CarParkService extends IService { 14 | 15 | boolean save(CarPark carPark); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/service/OrderService.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.example.demo.pojo.Order; 5 | 6 | /** 7 | * @title: OrderService 8 | * @projectName shardingdemo 9 | * @description: TODO 10 | * @author zhy 11 | * @date 2020/5/69:31 12 | */ 13 | public interface OrderService extends IService { 14 | 15 | /** 16 | * 创建表 17 | * @param tableName 18 | * @throws 19 | * @return void 20 | * @author zhy 21 | * @date 2020/5/11 16:17 22 | */ 23 | void createNewTable(String tableName); 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/service/impl/CarParkServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.service.impl; 2 | 3 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 4 | import com.example.demo.config.redis.RedisPrefixEnum; 5 | import com.example.demo.config.shardingconfig.ShardingRuleConfig; 6 | import com.example.demo.config.shardingconfig.ShardingService; 7 | import com.example.demo.config.shardingconfig.ShardingTableEnum; 8 | import com.example.demo.dao.CarParkMapper; 9 | import com.example.demo.pojo.CarPark; 10 | import com.example.demo.service.CarParkService; 11 | import com.example.demo.service.OrderService; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.data.redis.core.RedisTemplate; 14 | import org.springframework.stereotype.Service; 15 | import org.springframework.transaction.annotation.Transactional; 16 | 17 | import java.util.ArrayList; 18 | import java.util.Date; 19 | import java.util.Set; 20 | 21 | /** 22 | * @title: OrderServiceImpl 23 | * @projectName shardingdemo 24 | * @description: TODO 25 | * @author zhy 26 | * @date 2020/5/69:31 27 | */ 28 | @Service 29 | public class CarParkServiceImpl extends ServiceImpl implements CarParkService { 30 | @Autowired 31 | private CarParkMapper carParkMapper; 32 | 33 | @Autowired 34 | private RedisTemplate redisTemplate; 35 | 36 | @Autowired 37 | private ShardingService shardingService; 38 | 39 | @Autowired 40 | private OrderService orderService; 41 | 42 | 43 | @Override 44 | @Transactional 45 | public boolean save(CarPark carPark) { 46 | int insert = carParkMapper.insert(carPark); 47 | createTable(carPark.getId(),ShardingTableEnum.ORDER); 48 | saveRedis(carPark); 49 | return insert == 1; 50 | } 51 | 52 | private void saveRedis(CarPark carPark){ 53 | //获取老规则 54 | String oldOrderRule = shardingService.getActualDataNodesInRedis(ShardingTableEnum.ORDER); 55 | //将新增的停车场信息放入redis 56 | String allCarParkIdKey = RedisPrefixEnum.CAR_PARK_ID_CATALOG.getValue(); 57 | redisTemplate.opsForHash().put(allCarParkIdKey,carPark.getId(),carPark.getName()); 58 | //获取新规则 59 | String newOrderRule = shardingService.getActualDataNodesByCatalog(ShardingTableEnum.ORDER); 60 | shardingService.replaceActualDataNodes(oldOrderRule,newOrderRule); 61 | //根据时间将策略放进redis中,方便读取替换 62 | redisTemplate.opsForZSet().add(RedisPrefixEnum.SHARDING_RULE_ORDER.getValue(),newOrderRule,new Date().getTime()); 63 | } 64 | 65 | /** 66 | * 创建表 67 | * @param carParkId 68 | * @param shardingTableEnum 69 | * @throws 70 | * @return void 71 | * @author zhy 72 | * @date 2020/5/11 16:21 73 | */ 74 | private void createTable(String carParkId,ShardingTableEnum shardingTableEnum){ 75 | String orderTableName = shardingTableEnum.getValue() + "_" + carParkId; 76 | orderService.createNewTable(orderTableName); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/service/impl/OrderServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.service.impl; 2 | 3 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 4 | import com.example.demo.dao.OrderMapper; 5 | import com.example.demo.pojo.Order; 6 | import com.example.demo.service.OrderService; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Service; 9 | 10 | /** 11 | * @title: OrderServiceImpl 12 | * @projectName shardingdemo 13 | * @description: TODO 14 | * @author zhy 15 | * @date 2020/5/69:31 16 | */ 17 | @Service 18 | public class OrderServiceImpl extends ServiceImpl implements OrderService { 19 | @Autowired 20 | private OrderMapper orderMapper; 21 | 22 | /** 23 | * 创建表 24 | * @param tableName 25 | * @throws 26 | * @return void 27 | * @author zhy 28 | * @date 2020/5/11 16:17 29 | */ 30 | @Override 31 | public void createNewTable(String tableName) { 32 | orderMapper.createNewTable(tableName); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/services/org.apache.shardingsphere.orchestration.reg.api.RegistryCenter: -------------------------------------------------------------------------------- 1 | com.example.demo.config.shardingconfig.LocalRegistryCenter -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8086 3 | tomcat: 4 | max-threads: 100 5 | spring: 6 | druid: 7 | datasource: 8 | type: com.alibaba.druid.pool.DruidDataSource 9 | url: jdbc:mysql://192.168.4.71:3307/sharding_carPark?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai 10 | driver-class-name: com.mysql.jdbc.Driver 11 | username: root 12 | password: 123456 13 | maxActive: 20 14 | initialSize: 5 15 | maxWait: 60000 16 | minIdle: 5 17 | timeBetweenEvictionRunsMillis: 60000 18 | minEvictableIdleTimeMillis: 300000 19 | validationQuery: SELECT 1 FROM DUAL 20 | testWhileIdle: true 21 | testOnBorrow: false 22 | testOnReturn: false 23 | #是否缓存preparedStatement,也就是PSCache。在mysql下建议关闭。 PSCache对支持游标的数据库性能提升巨大,比如说oracle。 24 | poolPreparedStatements: false 25 | #要启用PSCache,-1为关闭 必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true 可以把这个数值配置大一些,比如说100 26 | maxOpenPreparedStatements: -1 27 | #配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙 28 | filters: stat,wall,log4j2 29 | #通过connectProperties属性来打开mergeSql功能;慢SQL记录 30 | connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 31 | #合并多个DruidDataSource的监控数据 32 | useGlobalDataSourceStat: true 33 | loginUsername: druid 34 | loginPassword: druid 35 | redis: 36 | database: 1 37 | host: 192.168.4.71 38 | port: 6379 39 | password: 123456 40 | jedis: 41 | pool: 42 | max-active: 8 43 | max-wait: -1 44 | max-idle: 8 45 | min-idle: 0 46 | logging: 47 | level: 48 | com.example.demo: debug 49 | -------------------------------------------------------------------------------- /src/test/java/com/example/demo/ShardingJavaDemoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class ShardingJavaDemoApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | --------------------------------------------------------------------------------