最近做两个项目的合并 类似的功能以及数据库 但是有表关系这块两个相差比较多 这样也会造成项目要修改大量的逻辑部分 容易引起更多BUG出现 本人也是为了偷懒 决定以A为主项目 进行操作
下面大概说下
A项目有aa数据库 B项目有一个bb数据库
功能:
由A项目操作B项目数据库(bb) 同时数据B 添加触发器 对A项目的aa数据库进行一些数据同步
第一步
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!-- =================================================================== -->
<!-- init.properties -->
<!-- =================================================================== -->
<bean id="placeholderConfig"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:../../config/init.properties</value>
</property>
</bean>
<!-- =================================================================== -->
<!-- c3p0 dataSource -->
<!-- =================================================================== -->
<!-- 数据源1-->
<bean id="dataSource"
class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass">
<value>${datasource.driver}</value>
</property>
<property name="jdbcUrl">
<value>${datasource.url}</value>
</property>
<property name="user">
<value>${datasource.username}</value>
</property>
<property name="password">
<value>${datasource.password}</value>
</property>
<!--连接池中保留的最小连接数。-->
<property name="minPoolSize">
<value>10</value>
</property>
<!--连接池中保留的最大连接数。Default: 1500 -->
<property name="maxPoolSize">
<value>1000</value>
</property>
<!--初始化时获取的连接数,取值应在minPoolSize与maxPoolSize之间。Default: 20 -->
<property name="initialPoolSize">
<value>20</value>
</property>
<!--最大空闲时间,10秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->
<property name="maxIdleTime">
<value>10</value>
</property>
<!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 10 -->
<property name="acquireIncrement">
<value>10</value>
</property>
<!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements
属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。
如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0-->
<property name="maxStatements">
<value>0</value>
</property>
<property name="maxStatementsPerConnection">
<value>0</value>
</property>
<!--每5小时检查所有连接池中的空闲连接。Default: 0 -->
<property name="idleConnectionTestPeriod">
<value>18000</value>
</property>
<!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 -->
<property name="acquireRetryAttempts">
<value>30</value>
</property>
<!--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效
保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试
获取连接失败后该数据源将申明已断开并永久关闭。Default: false-->
<property name="breakAfterAcquireFailure">
<value>false</value>
</property>
<!--因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的
时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable
等方法来提升连接测试的性能。Default: false -->
<property name="testConnectionOnCheckout">
<value>false</value>
</property>
<!--获取connnection时测试是否有效 -->
<property name="testConnectionOnCheckin">
<value>true</value>
</property>
<!--测试数据库连接的表名 -->
<property name="automaticTestTable">
<value>C3P0TestTable</value>
</property>
<!--定义所有连接测试都执行的测试语句。在使用连接测试的情况下这个一显著提高测试速度。
注意:测试的表必须在初始数据源的时候就存在。Default: null-->
<property name="preferredTestQuery">
<value>select * from C3P0TestTable</value>
</property>
</bean>
<!-- 数据源2-->
<bean id="zfdataSource"
class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass">
<value>${datasource.driver}</value>
</property>
<property name="jdbcUrl">
<value>${zf.datasource.url}</value>
</property>
<property name="user">
<value>${zf.datasource.username}</value>
</property>
<property name="password">
<value>${zf.datasource.password}</value>
</property>
<!--连接池中保留的最小连接数。-->
<property name="minPoolSize">
<value>10</value>
</property>
<!--连接池中保留的最大连接数。Default: 1500 -->
<property name="maxPoolSize">
<value>1000</value>
</property>
<!--初始化时获取的连接数,取值应在minPoolSize与maxPoolSize之间。Default: 20 -->
<property name="initialPoolSize">
<value>20</value>
</property>
<!--最大空闲时间,10秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->
<property name="maxIdleTime">
<value>10</value>
</property>
<!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 10 -->
<property name="acquireIncrement">
<value>10</value>
</property>
<!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements
属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。
如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0-->
<property name="maxStatements">
<value>0</value>
</property>
<property name="maxStatementsPerConnection">
<value>0</value>
</property>
<!--每5小时检查所有连接池中的空闲连接。Default: 0 -->
<property name="idleConnectionTestPeriod">
<value>18000</value>
</property>
<!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 -->
<property name="acquireRetryAttempts">
<value>30</value>
</property>
<!--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效
保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试
获取连接失败后该数据源将申明已断开并永久关闭。Default: false-->
<property name="breakAfterAcquireFailure">
<value>false</value>
</property>
<!--因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的
时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable
等方法来提升连接测试的性能。Default: false -->
<property name="testConnectionOnCheckout">
<value>false</value>
</property>
<!--获取connnection时测试是否有效 -->
<property name="testConnectionOnCheckin">
<value>true</value>
</property>
<!--测试数据库连接的表名 -->
<property name="automaticTestTable">
<value>C3P0TestTable</value>
</property>
<!--定义所有连接测试都执行的测试语句。在使用连接测试的情况下这个一显著提高测试速度。
注意:测试的表必须在初始数据源的时候就存在。Default: null-->
<property name="preferredTestQuery">
<value>select * from C3P0TestTable</value>
</property>
</bean>
<!-- =================================================================== -->
<!-- Hibernate sessionFactory -->
<!-- =================================================================== -->
<!-- session 1 -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"
destroy-method="destroy">
<property name="dataSource">
<ref local="dataSource" />
</property>
<property name="mappingResources">
<list>
<value>test/a/A.hbm.xml</valu
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.jdbc.fetch_size">${hibernate.jdbc.fetch_size}</prop>
<prop key="hibernate.jdbc.batch_size">${hibernate.jdbc.batch_size}</prop>
<prop key="hibernate.generate_statistics">${hibernate.generate_statistics}</prop>
<prop key="hibernate.connection.release_mode">${hibernate.connection.release_mode}</prop>
<prop key="hibernate.autoReconnect">${hibernate.autoReconnect}</prop>
<prop key="hibernate.cglib.use_reflection_optimizer">${hibernate.cglib.use_reflection_optimizer}</prop>
<prop key="hibernate.cache.use_query_cache">${hibernate.cache.use_query_cache}</prop>
<prop key="hibernate.cache.use_second_level_cache">${hibernate.cache.use_second_level_cache}</prop>
<prop key="hibernate.cache.provider_class">${hibernate.cache.provider_class}</prop>
</props>
</property>
</bean>
<!-- session 2 -->
<bean id="zfsessionFactory"class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"><property name="dataSource"><ref local="zfdataSource" /></property><property name="mappingResources"><list> <value>test/b/B.hbm.xml</value></list></property><property
name="hibernateProperties"><props><prop key="hibernate.show_sql">${hibernate.show_sql}</prop></props></property></bean><!-- =================================================================== --><!-- transactionManager --><!-- ===================================================================
--> <!-- 事务 1--><bean id="transactionManager"class="org.springframework.orm.hibernate3.HibernateTransactionManager"><property name="sessionFactory"><ref local="sessionFactory" /></property></bean> <!-- 事务 2-->
<bean id="zftransactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="zfsessionFactory" />
</property>
</bean>
<bean id="hibernateTemplate"
class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory"><ref bean="sessionFactory"/></property>
<property name="cacheQueries" value="${hibernate.cache.use_query_cache}"></property>
</bean>
<!-- =================================================================== -->
<!-- txProxyTemplate -->
<!-- =================================================================== -->
<bean id="transactionBase"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
lazy-init="true" abstract="true">
<!-- 配置事务管理器 -->
<property name="transactionManager" ref="zftransactionManager" />
<!-- 配置事务属性 -->
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<bean id="txProxyTemplate" abstract="true"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="transactionAttributes">
<props>
<!--
<prop key="Create*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="delete*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="Remove*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="update*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="validate*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="Invite*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="Log*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="Modify*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="permission*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="Initialize*">PROPAGATION_REQUIRED,-Exception</prop>
-->
<prop key="*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="save*">PROPAGATION_REQUIRES_NEW,-Exception</prop>
</props>
</property>
</bean>
</beans>
然后是要配置dao的注入
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="tblorganizationDAO" class="com.avonaco.dao.TblOrganizationDAO">
<property name="sessionFactory">
<ref bean="zfsessionFactory" />
</property>
</bean>
<!-- 数据源 1 session--> <bean id="A" class="test.a.A">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>
<!-- 数据源 2 session-->
<bean id="B" class="test.a.B">
<property name="sessionFactory">
<ref bean="zfsessionFactory" />
</property>
</bean>
</beans>
然后代码里去调用就可以了
这一有一点一定要注意.. 就是事务
当你在A项目中对B数据库进行了CUD操作 此时你在A数据库是可以查看到触发器同步过来的数据 但是你在A项目去获取aa数据库的数据 发现并没有改变
这是因为事务的关系 因为hibernate的事务 和 触发器的事务不是通过一个事务 我理解的原因是 当你修改了bb数据库 此时hibernate缓存中会更新bb数据库的数据 当时不会同步更新缓存中aa数据库的数据
因为在项目中用到了hibernate的乐观锁机制 发现在A项目只有你指定条件去查询这条数据数据的时候 乐观锁检查版本是否改变 从而进行更新
UPDATE A SET VERSION=?, name=? WHERE id=? AND VERSION=?此时你在页面操作A项目去修改bb数据库 页面上总是显示成功 但是你绝看不到页面上有任何数据进行了变化 而你数据库查看发现其实aa数据已经被同步过来了..
这就是因为事务不同步造成的
因为只是一些小模块的合并 所以暂时没有考虑是使用JTA事务 目前我的的做法是 当在A项目操作完bb数据库后 同时在根据操作条件查询一下aa数据库 从而达到他们的事务一致性 只是这样增加了数据库连接 如果在大量数据的时候 此方法肯定是不可行的..

本文探讨了在项目合并过程中,数据库之间的表关系差异导致的逻辑修改和BUG问题,介绍了如何利用A项目作为主操作数据库,同时通过触发器实现B项目数据库的同步更新。详细阐述了配置数据源、sessionFactory、事务管理器以及注入DAO的过程,强调了事务一致性的重要性。通过实例说明了在A项目操作B数据库后,同步更新AA数据库的方法,避免了事务不一致带来的问题。

2760

被折叠的 条评论
为什么被折叠?



