您觉得本文档还缺少什么内容?可以自己补充~
数据库相关的配置全部位于mysql.yml
bc:
mysql:
ip: 127.0.0.1
port: 3306
driverClassName: com.mysql.cj.jdbc.Driver
database: bc_column
username: 'root'
password: 'root'
url: jdbc:mysql://${bc.mysql.ip}:${bc.mysql.port}/${bc.mysql.database}?serverTimezone=CTT&characterEncoding=utf8&useUnicode=true&useSSL=false&autoReconnect=true&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&nullCatalogMeansCurrent=true
database: # 字段介绍参考 DatabaseProperties
multiTenantType: COLUMN
# COLUMN模式中隔离 租户 的列名
tenantIdColumn: tenant_code
# 是否不允许写入数据 WriteInterceptor
isNotWrite: false
# 是否启用 sql性能规范插件
isBlockAttack: false
# 是否启用 sql性能规范插件
isIllegalSql: false
# 是否启用分布式事务
isSeata: false
# 生产环境请设置p6spy = false
p6spy: true
# 分页大小限制
maxLimit: -1
# 数据库类型
dbType: MYSQL
# 溢出总页数后是否进行处理
overflow: true
# 生成 countSql 优化掉 join 现在只支持 left join
optimizeJoin: true
# 是否启用数据权限
isDataScope: true
# id生成策略
id-type: HU_TOOL
hutoolId:
workerId: 0
dataCenterId: 0
cache-id:
time-bits: 31
worker-bits: 22
seq-bits: 10
epochStr: '2020-09-15'
boost-power: 3
padding-factor: 50
# mysql 通用配置
spring:
autoconfigure:
exclude: org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
datasource:
dynamic:
enabled: false # 这里一定要写成false,无论是什么模式
druid:
enable: true
# 从这里开始(druid)
username: ${bc.mysql.username}
password: ${bc.mysql.password}
driver-class-name: ${bc.mysql.driverClassName}
url: jdbc:mysql://${bc.mysql.ip}:${bc.mysql.port}/${bc.mysql.database}?serverTimezone=CTT&characterEncoding=utf8&useUnicode=true&useSSL=false&autoReconnect=true&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&nullCatalogMeansCurrent=true
db-type: mysql
initialSize: 10 #初始的数据源链接数
minIdle: 10 # 最小连接池数量
maxActive: 200 # 最大连接池数量
max-wait: 60000 # 获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。
pool-prepared-statements: true # 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。
max-pool-prepared-statement-per-connection-size: 20 # 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100
validation-query: SELECT 'x' # 用来检测连接是否有效的sql,要求是一个查询语句,常用select 'x'。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。
test-on-borrow: false # 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
test-on-return: false # 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能
test-while-idle: true # 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
time-between-eviction-runs-millis: 60000 #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
min-evictable-idle-time-millis: 300000 #配置一个连接在池中最小生存的时间,单位是毫秒
filters: stat,wall # 属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有: 监控统计用的filter:stat 、 日志用的filter:log4j 、 防御sql注入的filter:wall
filter:
wall:
enabled: true
config:
commentAllow: true
multiStatementAllow: true
noneBaseStatementAllow: true
# 从这里结束(druid)
# 以下的2段配置,同时适用于所有模式
web-stat-filter: # WebStatFilter配置,说明请参考Druid Wiki,配置_配置WebStatFilter
enabled: true
url-pattern: /*
exclusions: "*.js , *.gif ,*.jpg ,*.png ,*.css ,*.ico , /druid/*"
session-stat-max-count: 1000
profile-enable: true
session-stat-enable: false
stat-view-servlet: #展示Druid的统计信息,StatViewServlet的用途包括:1.提供监控信息展示的html页面2.提供监控信息的JSON API
enabled: true
url-pattern: /druid/* #根据配置中的url-pattern来访问内置监控页面,如果是上面的配置,内置监控页面的首页是/druid/index.html例如:http://127.0.0.1:9000/druid/index.html
reset-enable: true #允许清空统计数据
login-username: bc
login-password: bc
allow: ''
禁止在控制台打印sql
bc:
database:
# 生产环境请设置p6spy = false
p6spy: true
调整在控制台打印的sql参数或格式
public class TenantP6SpyLogger implements MessageFormattingStrategy {
public static final String REGX = "[\\s]+";
@Override
public String formatMessage(int connectionId, String now, long elapsed, String category,
String prepared, String sql, String url) {
return StringUtils.isNotBlank(sql) ?
StrUtil.format(" tenant: {} userId: {} \n Consume Time:{} ms {} \n url: {} \n Execute SQL:{} \n",
ContextUtil.getTenant(), ContextUtil.getUserId(), elapsed, now, url, sql.replaceAll(REGX, StringPool.SPACE)) :
StringPool.EMPTY;
}
}
使用自定义sql时,如何优雅的写模糊查询参数
xml中自定义sql:
select * from user where 1=1 and name like #{keyword, typeHandler=fullLike} and account like #{keyword, typeHandler=leftLike} and describe like #{keyword, typeHandler=rightLike}
实际sql:
select * from user where 1=1 and name like '%张三%' and account like '%bc' and describe like '工作%'
原理:
FullLikeTypeHandler、LeftLikeTypeHandler、RightLikeTypeHandler
id、createdDate、createdBy、lastModifiedBy、lastModifiedDate 等字段如何自动填充 ?
- 原理:
- 实现元对象处理器接口:BcMetaObjectHandler
- 注解填充字段
@TableField(.. fill = FieldFill.INSERT)
生成器策略部分也可以配置!
public class User {
// 注意!这里需要标记为填充字段
@TableField(.. fill = FieldFill.INSERT)
private String fillField;
....
}
集群部署如何配置雪花id规则? 为什么id为重复?
bc:
database:
id-type: HU_TOOL # HU_TOOL、 DEFAULT、CACHE
hutoolId:
workerId: 0
dataCenterId: 0
cache-id:
time-bits: 31
worker-bits: 22
seq-bits: 10
epochStr: '2020-09-15'
boost-power: 3
padding-factor: 50
雪花id生成类型有3种: HU_TOOL、DEFAULT、CACHE
- HU_TOOL: 使用hutool 提供的雪花生成算法,集群部署时,需要保证每个节点读取到的
bc.database.hutoolId.workerId
或bc.database.hutoolId.dataCenterId
不一样,否则可能会造成id重复问题 。 - DEFAULT:UidGenerator通过借用未来时间来解决sequence天然存在的并发限制。
- CACHE( 推荐使用 ):采用RingBuffer来缓存已生成的UID, 并行化UID的生产和消费, 同时对CacheLine补齐,避免了由RingBuffer带来的硬件级「伪共享」问题 。
其中 DEFAULT、CACHE 依赖于 worker_node
表, 工作原理是: 每次启动项目时,自增一条数据,使用自增id 作为雪花id的 workerId ,避免了集群部署时,动态扩展和缩减节点,需要手动配置不同的workerId 的问题。 而CACHE模式,是在DEFAULT模式的基础上做了缓存,性能更好。 所以集群部署,尤其是需要动态扩容时,强烈建议使用 CACHE 模式。
如何在 SuperMapper 中,增加方法
在SuperMapper中定义方法接口,如:
/** * 全量修改所有字段 * @param entity 实体 * @return 修改数量 */ int updateAllById(@Param(Constants.ENTITY) T entity);
定义 updateAllById 方法的动态sql. (具体的实现代码位于: AlwaysUpdateSomeColumnById )
@NoArgsConstructor
public class UpdateAllById extends AlwaysUpdateSomeColumnById {
public UpdateAllById(Predicate<TableFieldInfo> predicate) {
super(predicate);
}
@Override
public String getMethod(SqlMethod sqlMethod) {
// 自定义 mapper 方法名
return "updateAllById";
}
}
- 注入 UpdateAllById
public class BcSqlInjector extends DefaultSqlInjector {
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);
methodList.add(new UpdateAllById(field -> !ArrayUtil.containsAny(new String[]{
SuperEntity.CREATE_TIME_COLUMN, SuperEntity.CREATED_BY_COLUMN
}, field.getColumn())));
return methodList;
}
}
- 配置 BcSqlInjector
@Bean
@ConditionalOnMissingBean
public BcSqlInjector getMySqlInjector() {
return new BcSqlInjector();
}