Activiti数据库表结构⼤⼩写转换(springMVCspringBoot)
Activiti 数据库表结构⼤⼩写转换
背景
项⽬中使⽤了activiti,activiti使⽤mysql作为数据源。上线时被DBA卡住了,原因是⼤写的表结构不符合sql规范,⼀番沟通后⽆果,⽆奈只能⾃⼰想办法解决了。经过⼀番探索,最终成功解决表结构⼤写问题,现总结如下。
注:⾸先你肯定需要⾃⼰将建表语句改为⼩写,然后创建对应的表,这⾥需要注意的⼀点是
act_ge_property
需要有初始化数据,否则项⽬⽆法正常启动。
实操
修改数据库服务
这个是最直接也最简单的⽅式,直接修改数据库服务,使其⼤⼩写不敏感。
打开myf⽂件,加⼊以下语句后重启。
lower_case_table_names = 1
但是此⽅法受是否可操作服务器的局限。很明显,这个⽅法在我这这⾥⾏不通。
利⽤处理
使⽤mybatis的在向数据库发送sql的时候进⾏拦截,将其转换为⼩写的语句。
使⽤
1. 定义 xxInterceptor 使其实现 mybatis的 Interceptor接⼝;
2. 在mybaits的全局配置⽂件中,声明这个插件。
@Intercepts({
@Signature(
type = StatementHandler.class, method ="prepare", args ={Connection.class, Integer.class
})
})
@Component
public class MySqlInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation)throws Throwable {
StatementHandler statementHandler =(StatementHandler) Target();
BoundSql boundSql = BoundSql();
//获取到原始sql语句
String sql = Sql();
sql =convertTableNameToLower(sql);
Field field = Class().getDeclaredField("sql");
field.setAccessible(true);
field.set(boundSql, sql);
return invocation.proceed();
}
@Override
public Object plugin(Object o){
return Plugin.wrap(o,this);
}
private String convertTableNameToLower(String sql){
//TODO 对sql进⾏处理
return sql;
}
@Override
public void setProperties(Properties properties){
}
}
<!-- MyBatis全局配置⽂件:l -->
<plugins>
<plugin interceptor="x.MySqlInterceptor">
<!--此处可以定义⼀些⽤得着的属性-->
<property name="propertyXXX"value="valueXXX"/>
spring mvc和boot区别
</plugin>
</plugins>
OK,此时⼀个sql就定义好了,启动项⽬试试吧。
没错,正如你期待的那样。如果你的表结构此时已经改成⼩写了,那么在启动的时候项⽬会报错,告诉你表不存在。但是,到这肯定不⽢⼼啊,我的到底⽣效了没,是不是⽩搞了。于是,我为了项⽬能起来,做了如下操作
先把表全部⼲掉,让activiti启动的时候⾃⼰创建表,
等项⽬起来以后,再把系统⾃动创建的⼤写的表⼲掉,改成⾃⼰定义的⼩写表。
此时再测试⼀下(在⾃⼰定义的那块加个断点试试),没错,进来了,数据也正常写⼊了。⾄少取得了阶段性胜利。
思考:为什么项⽬启动的时候未⽣效,⽽在正常启动之后可以正常运⾏?
补充:的添加是通过sqlSessionFactory添加的
猜测是activiti⾃⼰对mybatis的SqlSessionFactory做了封装,并且与mybatis的默认DefaultSqlSessionFactory建⽴了联系。在启动的时候使⽤⾃⼰的SqlSessionFactory,项⽬启动之后DefaultSqlSessionFactory也初始化完成,此时的DefaultSqlSessionFactory已经加载了⾃定义的。⾃定义的与默认的⼜建⽴了联系,所以启动后可以正常使⽤。
后来的探索也验证了这⼀点。activiti⾃⼰维护了⼀个DbSqlSessionFactory。
那如果我能在DbSqlSessionFactory这个上⾯添加我⾃定义的,那应该就可以正常使⽤了。
通过源码窥探实现⽅案
从这⾥⼊⼿
ine.impl.cfg.ProcessEngineConfigurationImpl#init
public void init(){
this.initConfigurators();
// ……
}
查看initConfigurators⽅法
public void initConfigurators(){
this.allConfigurators =new ArrayList();
//加载默认的configurators
figurators != null){
Iterator var1 =figurators.iterator();
while(var1.hasNext()){
ProcessEngineConfigurator configurator =(();
this.allConfigurators.add(configurator);
}
}
ableConfiguratorServiceLoader){
ClassLoader classLoader =ClassLoader();
//加载⾃定义的configurators
ServiceLoader<ProcessEngineConfigurator> configuratorServiceLoader = ServiceLoader.load(ProcessEngineConfigurator.class, classLoader);
for(var4 = configuratorServiceLoader.iterator(); var4.hasNext();++nrOfServiceLoadedConfigurators){
// ……
this.allConfigurators.add(configurator);
}
//……
}
}
为了查看清晰,代码仅保留了我们需要关注的内容,此处主要做了两件事情
加载默认的configurators添加⾄allConfigurators
加载⾃定义的configurators添加⾄allConfigurators
加载⾃定义配置的时候,注意到ProcessEngineConfigurator
public interface ProcessEngineConfigurator {
void beforeInit(ProcessEngineConfigurationImpl var1);
void configure(ProcessEngineConfigurationImpl var1);
int getPriority();
}
然后在configuratorsBeforeInit()及configuratorsAfterInit()中分别调⽤了beforeInit()及configure()⽅法。
SqlSessionFactory sqlSessionFactory = SqlSessionFactory();
拿到sqlSessionFactory就好办了。
正如上⽂ “补充” 中提到,只要通过
添加即可。接下来开始⾃定义configurators
1. 实现ProcessEngineConfigurator(这⾥选择extend ProcessEngineConfigurator的抽象类AbstractProcessEngineConfigurator)public class MyProcessEngineConfigurator extends AbstractProcessEngineConfigurator {
public void configure(ProcessEngineConfigurationImpl processEngineConfiguration){
SqlSessionFactory sqlSessionFactory = SqlSessionFactory();
//这⾥是⾃定义的MySqlInterceptor,跟上⽂⼀样
}
}
2. 添加到配置⽂件
<bean id="processEngineConfiguration"class="org.activiti.spring.SpringProcessEngineConfiguration">
<!--
……
-->
<property name="configurators">
<list>
<bean class="MyProcessEngineConfigurator"></bean>
</list>
</property>
</bean>
如果是springBoot的项⽬,直接使⽤配置类的⽅式
@Configuration
public class MyAbstractProcessEngineConfigurator implements ProcessEngineConfigurationConfigurer {
@Override
public void configure(SpringProcessEngineConfiguration springProcessEngineConfiguration){
List<ProcessEngineConfigurator> list =new ArrayList<>();
list.add(new MyProcessEngineConfigurator());
springProcessEngineConfiguration.setConfigurators(list);
}
}
这样,在项⽬启动的时候,就可以将⾃定义的加载进activiti内,⾄此,改造结束。
DbSqlSessionFactory&sqlSessionFactory
activiti⾃⼰维护的DbSqlSessionFactory与mybatis的sqlSessionFactory的关系是如何维护的呢?
public void init(){
this.initConfigurators();
// ……
if(this.usingRelationalDatabase){
this.initSqlSessionFactory();
}
this.initSessionFactories();
// ……
}
看到这⾥initSqlSessionFactory,创建mybatis的DefaultSqlSessionFactory
public void initSqlSessionFactory(){
if(this.sqlSessionFactory == null){
InputStream inputStream = null;
try{
inputStream =MyBatisXmlConfigurationStream();
Environment environment =new Environment("default",ansactionFactory,this.dataSource);
Reader reader =new InputStreamReader(inputStream);
Properties properties =new Properties();
properties.put("prefix",this.databaseTablePrefix);
String wildcardEscapeClause ="";
if(this.databaseWildcardEscapeCharacter != null &&this.databaseWildcardEscapeCharacter.length()!=0){ wildcardEscapeClause =" escape '"+this.databaseWildcardEscapeCharacter +"'";
}
properties.put("wildcardEscapeClause", wildcardEscapeClause);
properties.put("limitBefore","");
properties.put("limitAfter","");
properties.put("limitBetween","");
properties.put("limitOuterJoinBetween","");
properties.put("limitBeforeNativeQuery","");
properties.put("orderBy","order by ${orderByColumns}");
properties.put("blobType","BLOB");
properties.put("boolValue","TRUE");
if(this.databaseType != null){
properties.ResourceAsStream("org/activiti/db/properties/"+this.databaseType +".properties"));
}
Configuration configuration =this.initMybatisConfiguration(environment, reader, properties);
this.sqlSessionFactory =new DefaultSqlSessionFactory(configuration);
}catch(Exception var10){
throw new ActivitiException("Error while building ibatis SqlSessionFactory: "+ Message(), var10);
}finally{
IoUtil.closeSilently(inputStream);
}
}
}
然后将DefaultSqlSessionFactory赋给dbSqlSessionFactory
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论