最近做两个项目的合并 类似的功能以及数据库 但是有表关系这块两个相差比较多 这样也会造成项目要修改大量的逻辑部分 容易引起更多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数据库 从而达到他们的事务一致性 只是这样增加了数据库连接 如果在大量数据的时候 此方法肯定是不可行的..