最近项目中有一种需求: 大致需求是这样的 通过给定的 用户名和密码 要定时从远程的数据库中取数据,然后把取出来的数据插入或更新本地的oracle数据库的表 项目的结构式struts1 hibernate spring 这里使用spring的定时来处理,自己写了个项目进行测试,目前项目可以跑的通, 在测试当中遇到了问题,就是使用 spring 提供的jdbcTemplate进行操作数据,使用的是dbcp数据源,可以查询到数据,但是inert update delete 操作数据时,看起来成功了,但是数据库中的数据并没有变化, 查了很多的资料,偶然发现 有人说 dbcp数据源的事务不是自动提交,所以看不到效果, 改用c3p0数据源之后,的确是好了 后来发现在使用dbcp数据源时 把事务的自动提交功能给关闭了 <property name="defaultAutoCommit"> <value>false</value> 定时任务的核心代码开始 项目的组织结构
< 图1 >
< 图2 >
任务类有1个:JobClass.java 该类的任务就是从定时从sqlserver中取出数据,然后更新oracle中数据 JobClass.java package com.sinovatech.news.datatransjob; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.springframework.jdbc.core.BatchPreparedStatementSetter; import org.springframework.jdbc.core.JdbcTemplate; import com.sinovatech.news.model.dto.CmsCyUser; public class JobClass{ private JdbcTemplate jdbcTemplate_oracle; private JdbcTemplate jdbcTemplate_sqlserver; /** * 1. 定时操作:定时从sqlserver中取数据,更新数据库 * 2. 方法以TX结尾时 使用事务的一个条件 , * spring中的bean要使用下面的配置方法 * <bean id="jobClass" parent="baseTransactionProxy"> <property name="target"> <bean class="com.sinovatech.news.datatransjob.JobClass"> <property name="jdbcTemplate_oracle"> <ref bean="jdbcTemplate_oracle"/> </property> <property name="jdbcTemplate_sqlserver"> <ref bean="jdbcTemplate_sqlserver"/> </property> </bean> </property> </bean> */ public void myJobTX() { List<CmsCyUser> cmsCyUsers = getData(); updateTicketInfo(cmsCyUsers); } /** * 更新oracle中CMS_CY_USER表的数据, * 使用BatchPreparedStatementSetter进行批处理 * @param users */ public void updateTicketInfo(List<CmsCyUser> users) { if(users==null||users.size()==0){ return; } final List<CmsCyUser> cyUsers = users; String sql = "update CMS_CY_USER set tickets=? where race_num=?"; jdbcTemplate_oracle.batchUpdate(sql, new BatchPreparedStatementSetter() { public void setValues(PreparedStatement ps, int i) throws SQLException { CmsCyUser user = cyUsers.get(i); ps.setInt(1, user.getTickets().intValue()); ps.setString(2, user.getRaceNum()); } public int getBatchSize() { return cyUsers.size(); } }); resetTickets(users,jdbcTemplate_oracle); } /** * 把没有race_num对应的tickets数据清零 * @param users * @param jdbcTemplateOracle */ private void resetTickets(List<CmsCyUser> users,JdbcTemplate jdbcTemplateOracle) { if(users==null||jdbcTemplateOracle==null){ return; } StringBuffer buffer = new StringBuffer(); buffer.append("("); for(int i=0;i<users.size()-1;i++ ){ buffer.append("'"+users.get(i).getRaceNum()+"',"); } buffer.append("'"+users.get(users.size()-1).getRaceNum()+"')"); String sql = "update CMS_CY_USER set tickets=0 where race_num not in "+buffer.toString(); jdbcTemplateOracle.update(sql); } /** * 从sqlserver中取出数据 * @return */ public List<CmsCyUser> getData() { List<CmsCyUser> userList = new ArrayList<CmsCyUser>(); List list = null; String sql = "SELECT race_num,tickets FROM ticketinfo"; list = jdbcTemplate_sqlserver.queryForList(sql); if (!list.isEmpty() && list != null && list.size() > 0) { for (int i = 0; i < list.size(); i++) { Object obj = list.get(i); String[] ticketInfos = obj.toString().split(","); // 因为只有2个值,所以直接使用下标来处理 String raceNum = ticketInfos[0].replaceAll("\s*", ""); // 过滤掉含有中文的非法编号 if (isContainsChinese(raceNum)) { continue; } String tickets = ticketInfos[1]; int b2 = tickets.indexOf('}'); int b1 = tickets.indexOf('='); int a = raceNum.indexOf('='); CmsCyUser user = new CmsCyUser(); raceNum = raceNum.substring(a + 1); tickets = tickets.substring(b1 + 1, b2); user.setRaceNum(raceNum); user.setTickets(Long.parseLong(tickets)); userList.add(user); } } System.out.println("..successful.."); return userList; } /** * 判断字符串中是否含有中文字符 * @param str * @return */ public boolean isContainsChinese(String str) { Matcher matcher = Pattern.compile("[u4e00-u9fa5]").matcher(str); boolean flg = false; if (matcher.find()) { flg = true; } return flg; } public JdbcTemplate getJdbcTemplate_sqlserver() { return jdbcTemplate_sqlserver; } public void setJdbcTemplate_sqlserver(JdbcTemplate jdbcTemplateSqlserver) { jdbcTemplate_sqlserver = jdbcTemplateSqlserver; } public JdbcTemplate getJdbcTemplate_oracle() { return jdbcTemplate_oracle; } public void setJdbcTemplate_oracle(JdbcTemplate jdbcTemplateOracle) { jdbcTemplate_oracle = jdbcTemplateOracle; } }
调用任务的类
MyJob.java
package com.sinovatech.news.datatransjob; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.springframework.scheduling.quartz.QuartzJobBean; /** * spring 定时任务 * #####spring 定时任务需要继承QuartzJobBean 这种方式是最常用的! * #####同时就实现了抽象方法executeInternal * */ public class MyJOb extends QuartzJobBean{ private JobClass jobClass; public void setJobClass(JobClass jobClass) { this.jobClass = jobClass; } /** * 调用自定义的任务 */ @Override protected void executeInternal(JobExecutionContext context) throws JobExecutionException { jobClass.myJobTX(); } }
Spring的相关的配置信息
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath:jdbc.properties</value> </list> </property> </bean> <!—定义oracle的连接 此处使用dbcp数据源--> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName"> <value>${jdbc.driverClassName}</value> </property> <property name="url"> <value>${jdbc.url}</value> </property> <property name="username"> <value>${jdbc.username}</value> </property> <property name="password"> <value>${jdbc.password}</value> </property> <property name="maxActive"> <value>100</value> </property> <property name="maxIdle"> <value>3</value> </property> <property name="maxWait"> <value>-1</value> </property> <!-- 个人认为此处最后开启数据源事务自动提交功能--> <property name="defaultAutoCommit"> <value>true</value> </property> </bean> <!—定义oracle的SessionFactory--> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="lobHandler"> <ref bean="oracleLobHandler" /> </property> <property name="dataSource"> <ref local="dataSource" /> </property> <property name="mappingDirectoryLocations"> <list> <value>classpath:/hbm</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect"> org.hibernate.dialect.Oracle9iDialect </prop> <prop key="hibernate.jdbc.batch_size">0</prop> <prop key="hibernate.format_sql">true</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.hbm2ddl.auto">update</prop> </props> </property> </bean> <!-- ****************************** 新增sqlserver的数据源和 sessionFactory的配置 begin *************************************************--> <!—sqlserver 的连接,使用dbcp 数据源--> <bean id="dataSource_sqlserver" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName"> <value>${sqlserver.driver}</value> </property> <property name="url"> <value>${sqlserver.url}</value> </property> <property name="username"> <value>${sqlserver.username}</value> </property> <property name="password"> <value>${sqlserver.password}</value> </property> <property name="maxActive"> <value>100</value> </property> <property name="maxIdle"> <value>3</value> </property> <property name="maxWait"> <value>-1</value> </property> <!-- 个人认为此处最后开启数据源事务自动提交功能--> <property name="defaultAutoCommit"> <value>true</value> </property> </bean> <bean id="sessionFactory_sqlserver" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource_sqlserver" /> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop> <prop key="hibernate.connection.autocommit">true</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.format_sql">true</prop> <prop key="hibernate.hbm2ddl.auto">validate</prop> </props> </property> </bean> <!-- ****************************** 新增sqlserver的数据源和 sessionFactory的配置 end *************************************************--> <!—定义事务处理--> <bean id="baseTransactionProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true"> <property name="transactionManager"> <ref bean="transactionManager" /> </property> <property name="transactionAttributes"> <props> <prop key="*RTX">PROPAGATION_REQUIRED,readOnly</prop> <prop key="*TX">PROPAGATION_REQUIRED</prop> </props> </property> </bean> <!—定义oracle的事务管理 ,该事务处理的bean会被引用--> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory"> <ref local="sessionFactory" /> </property> </bean> <!--*********************************** 定时任务相关配置 begin ***********************************--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"/> </bean> <bean id="jdbcTemplate_oracle" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"/> </bean> <bean id="jdbcTemplate_sqlserver" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource_sqlserver"/> </bean> <!-- 把数据写入oracle,此处使用了事务管理 --> <bean id="jobClass" parent="baseTransactionProxy"> <property name="target"> <bean class="com.sinovatech.news.datatransjob.JobClass"> <property name="jdbcTemplate_oracle"> <ref bean="jdbcTemplate_oracle"/> </property> <property name="jdbcTemplate_sqlserver"> <ref bean="jdbcTemplate_sqlserver"/> </property> </bean> </property> </bean> <!-- 基础的配置 相关类的注入 --> <bean class="org.springframework.scheduling.quartz.JobDetailBean" id="MyTimeSpringJob"> <property name="jobClass" value="com.sinovatech.news.datatransjob.MyJOb"/> <!-- value中配置的是自定义的任务类 --> <property name="jobDataAsMap"><!-- 所有的任务类都可以写在map中,当定时任务中需要注入别的bean的时候,就可以在这里注入,我里面输入了一个jobClass类 --> <map> <entry key="jobClass" value-ref="jobClass"/> </map> </property> </bean> <!-- 相关的时间配置 --> <bean class="org.springframework.scheduling.quartz.SimpleTriggerBean" id="MyTimesimpleTriggerBean"> <property name="jobDetail" ref="MyTimeSpringJob"/> <!-- 给MyTimeSpringJob配置时间信息,name的jobDetail是spring内部需要注入的名字 --> <property name="repeatInterval" value="300000"/> <!--相隔1000毫秒执行一次 --> <property name="startDelay" value="3000"/> <!--应用服务器启动3000毫秒后开始执行任务 --> </bean> <!-- ***启动定时任务*** --> <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref bean="MyTimesimpleTriggerBean"/> </list> </property> </bean> <!--*********************************** 定时任务相关配置 end ***********************************--> </beans>
数据库的配置文件Jdbc.properties(在src下面)
jdbc.driverClassName=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:@127.0.0.1:1521:orcl
jdbc.username=jxbms
jdbc.password=jxbms
sqlserver.username=sa
sqlserver.password=sqlserver
sqlserver.url=jdbc:jtds:sqlserver://localhost:1433/J2EE
sqlserver.driver=net.sourceforge.jtds.jdbc.Driver
定时任务的核心代码结束