0 0

spring多线程调用存储过程后出现无法连接数据库5

本人用的oracle


场景是这样的: 用spring做了一个定时任务,每20分钟调用一次,每次调用的时候读一个配置文件来切换数据源。

每切换一次数据源开启一个线程调用一次存储过程,

每个不同数据源的存储过程都往同一个目标数据库里面灌数据来达到数据同步的效果。

 

 

 



问题:  

   1:但任务启动是,目标数据库的session增多,好似没有释放。  

   2:当运行一天后,plsql无法连接目标数据库。

 

 

 

本人对问题的分析可能性:    1:oracle的session中inactive的会话导致.

                                        2:每个线程调用存储过程后资源没有释放。(原因:停止服务器后oracle的session减少)

                                        3:线程在切换数据源后,spring的单例没起作用。(不断不断的去连接,直到超过连接数)。

 

 

请大虾们分析。 

 

 

一下是spring的代码

 

<!-- 数据源配置start -->
	<bean id="parentDataSource" class="org.apache.commons.dbcp.BasicDataSource" >  
            <property name="maxIdle" value="20" ></property>
		    <property name="maxActive" value="50" ></property>
		    <property name="maxWait" value="3000" />
		    <property name="minIdle" value="10" />
		    <property name="removeAbandoned" value="true"/>
		    <property name="removeAbandonedTimeout" value="60"/>
    </bean>
	
	<bean id="cx_dataSource" class="com.changx.ds.DynamicDataSource">   
        <property name="targetDataSources">    
          <map key-type="java.lang.String">  
             <entry key="cx_4306020_xx" value-ref="cx_4306020_xx"/>
             <entry key="cx_4306021_xx" value-ref="cx_4306021_xx"/>
            
             
             
          </map>    
       </property>    
       <property name="defaultTargetDataSource" ref="cx_4306021_xx"/>    
    </bean> 
    
   
        <bean id="cx_4306020_xx" parent="parentDataSource">
        <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
        <property name="url" value="jdbc:oracle:thin:@192.1.2.145:1521:orclzhs" />
        <property name="username" value="cx_4306020" />
        <property name="password" value="4306020" />
    </bean>
    
    <bean id="cx_4306021_xx" parent="parentDataSource">
        <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
        <property name="url" value="jdbc:oracle:thin:@192.1.2.145:1521:orclzhs" />
        <property name="username" value="cx_4306021" />
        <property name="password" value="4306021" />
    </bean>

 

 

线程调用的类

 

 

public class TaskExecutorExample implements TaskExecutorInterface{  
    
    private TaskExecutor taskExecutor;  
    private CallProduce callPro;
    public CallProduce getCallPro() {
        return callPro;
    }
    public void setCallPro(CallProduce callPro) {
        this.callPro = callPro;
    }
    public TaskExecutorExample(TaskExecutor taskExecutor) {      
        this.taskExecutor = taskExecutor;    
    }  
      
 
    private class CallProduceTask implements Runnable {      
        private String dbStr;   
 
        public CallProduceTask(String dbStr) {        
            this.dbStr = dbStr;      
        }  
        
        public void run() {    
            CustomerContextHolder.setCustomerType("cx_"+dbStr);
            callPro.tranData();
            callPro.call_send_joindata_to_front();
            System.out.println("---运行over--"+dbStr);      
        }  
    }

    
    /**
     * 调用存储过程
     */
    public void executeProdure() {
        Set dsSet=ProperUtil.properds.keySet();
        String dbStr= "";
        for(Iterator i=dsSet.iterator();i.hasNext();){
            dbStr = i.next().toString();
            //System.out.println(dbStr);
            taskExecutor.execute(new CallProduceTask(dbStr)); 
        }

    
    }



     
}  
 

 

调用的dao

 

public class CallProduceImpl extends JdbcDaoSupport implements CallProduce {
    
	/**
	 * 数据标化
	 */
	public void tranData() {
		// TODO Auto-generated method stub
	    //CustomerContextHolder.setCustomerType("cx_"+dbStr);
		//System.out.println("---开始执行---"+CustomerContextHolder.getCustomerType());
		Connection conn=null;
		String qx = CustomerContextHolder.getCustomerType();
		try {
			
			//List list = this.getJdbcTemplate().queryForList("select count(1) from t107_referral t");
			//System.out.println(list.get(0).toString());
			
			List sb_ywb_list = this.getJdbcTemplate().queryForList("select hospital_id,ywid,id,flag from sb_send_dyywb where send_flag='0'");
			conn=this.getJdbcTemplate().getDataSource().getConnection();
			
			for(int i=0;i<sb_ywb_list.size();i++){

                Map map=(Map)(sb_ywb_list.get(i));
                //System.out.println(map.get("hospital_id")+"-----"+map.get("ywid")+"==="+map.get("ywid"));
                
                String hospital_id = map.get("hospital_id").toString();
                String ywid  = map.get("ywid").toString();
                String id = map.get("id").toString();
                
                String pro_str = "";
                if(map.get("flag").toString().trim().equals("i")||map.get("flag").toString().trim().equals("I")){
                  //send_dyywb_insert(i.hospital_id, i.ywid, i.id, vs_flag, vs_str);
                    pro_str = "{call pkg_standard.send_dyywb_insert(?,?,?,?,?)}";
                    
                }else if(map.get("flag").toString().trim().equals("u")||map.get("flag").toString().trim().equals("U")){
                    // send_dyywb_update(i.hospital_id, i.ywid, i.id, vs_flag, vs_str);
                    pro_str = "{call pkg_standard.send_dyywb_update(?,?,?,?,?)}";
                }
                
                
                CallableStatement cs=conn.prepareCall(pro_str);
                cs.setString(1, hospital_id);
                cs.setString(2, ywid);
                cs.setString(3, id);
                cs.registerOutParameter(4, Types.VARCHAR);//vs_flag
                cs.registerOutParameter(5, Types.VARCHAR);//vs_str
                cs.execute();
                
                
                String  vs_flag = cs.getString(4);
                String  vs_str = cs.getString(5);
                
                
                System.out.println("qx:"+qx+",返回标志:"+vs_flag+"返回值:"+vs_str);
                if("0".equals(vs_flag)){
                    String delSql = "delete from sb_send_dyywb  where hospital_id = '"+hospital_id+"' and ywid = '"+ywid+"' and id = '"+id+"'";
                    this.getJdbcTemplate().execute(delSql);
                    
                    conn.commit();
                }else{
                    conn.rollback();
                    
//                    String temp =  vs_str + ",hospital_id:" + hospital_id + ",ywid:" + ywid +",id:" + id;
//                    String exceptionSql = "insert into xt_ywrzb values (seq_ywrz.nextval,  'send_data',  '1', sysdate,'"+temp+"', '','1','cx', 'send_dyywb_to_front')";
//                    java.sql.Statement ps = conn.createStatement();
//                    //System.out.println("错误日志:"+exceptionSql);
//                    ps.execute(exceptionSql);
                    
                }
			}
			
		} catch (SQLException e) {
		    System.out.println("---这个连接无法获得:"+CustomerContextHolder.getCustomerType());
			try {
				conn.rollback();
			} catch (SQLException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			if(conn!=null){
				try {
				    System.out.println("关闭连接!");
					conn.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		
	}

}
 

 

 

 

请大虾们指点下。

2012年7月13日 11:39

5个答案 按时间排序 按投票排序

0 0

<bean id="parentDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
另外这个可以看下
http://cuisuqiang.iteye.com/blog/1508759

2012年7月14日 21:59
0 0

       CallableStatement cs=conn.prepareCall(pro_str);   41.                cs.setString(1, hospital_id);  
42.                cs.setString(2, ywid);  
43.                cs.setString(3, id);  
44.                cs.registerOutParameter(4, Types.VARCHAR);//vs_flag  
45.                cs.registerOutParameter(5, Types.VARCHAR);//vs_str  
46.                cs.execute(); 
这段代码放在循环里面里面?下划线部分一直在创建没有关闭。数据量多数据当然会出问题
你在cs.execute(); 
后加上cs.close()试试。

2012年7月13日 22:29
0 0

quartz默认是一次开10个线程,我觉得好使的就是cron表达式,其他的timer基本就能解决了
还有楼主这个存储过程执行的时间要过久
这样调用存储过程,如果时间过程,可能导致线程timeout,而不去释放连接

2012年7月13日 16:48
0 0

定时任务本身就会启动线程
你这个问题肯定是线程数量过大导致的。
如果要用你自己的线程,也不要总是新建线程, 配置一个线程池(spring自带线程池,可以百度一下,很简单), 然后使用配置好的线程池来启动线程。

2012年7月13日 15:56
0 0

线程创建后有没有关闭?定时器会自动创建线程的吧?

2012年7月13日 13:08

相关推荐

    Spring+Hibernate下的数据库连接动态切换

    需求场景为:用户在登录过程中可以选择或指定自己的数据库名称,登录成功后,后续的所有数据库操作都将基于该选定的数据库执行。此外,用户在会话期间还能够更改所使用的数据库连接。 #### 三、技术选型 为了实现这...

    java JDBC连接数据库代码大全

    - `prepareCall(String sql)`:创建一个`CallableStatement`对象,用于调用数据库中的存储过程。 3. **`Statement`**:用于执行简单SQL语句的接口。 - `executeQuery(String sql)`:执行查询语句,并返回结果集`...

    Java中数据库连接池原理机制的详细讲解

    - 为了保证连接池在多线程环境下的安全性,连接池通常采用`synchronized`关键字或其他同步机制来保护关键代码段,防止并发访问时出现的问题。 ```java public synchronized Connection getConnection() { // ...

    springboot多数据源连接

    在Spring Boot应用中,多数据源连接是一种常见的需求,尤其在大型系统中,可能需要连接到不同的数据库以实现数据隔离、读写分离或是利用不同类型的数据库特性。本项目提供了实现这一功能的示例,可以直接使用,同时...

    springmvc多数据库

    在大型项目中,由于业务需求,往往需要接入多个数据库,例如Oracle,来处理不同的数据源。本篇文章将深入探讨如何在SpringMVC中集成MyBatis以实现多数据库的支持。 首先,我们需要理解SpringMVC的角色。SpringMVC是...

    基于Java实现爬虫JD评论基于Spring boot 加JPA MySQL数据库

    3. **异步与多线程**: 为了提高爬取效率,可以使用Java的并发库,如ExecutorService,实现多线程或异步爬取。 **Spring Boot集成** 1. **Spring Boot初始化**: 创建一个新的Spring Boot项目,引入Web、Data JPA和...

    Spring事务处理-ThreadLocal的使用

    通过深入源码学习,我们可以更好地理解Spring如何在多线程环境中优雅地管理事务,以及如何利用ThreadLocal来优化并发性能。同时,了解数据库连接池的工作原理也有助于我们更好地配置和使用连接池,提升应用程序的...

    springboot-AOP实现多数据源动态切换(Druid连接池)

    这个切面可以利用ThreadLocal变量来存储当前线程所使用的数据源标识,确保在同一个线程内,对数据库的操作使用相同的连接。具体实现中,需要定义一个Pointcut来指定哪些方法触发数据源切换,以及一个Advice来执行...

    基于Spring+Ibatis的安全线程实现

    在这个场景下,我们关注的重点是如何在多线程环境下正确地使用这两者,避免出现数据竞争或其他线程不安全的情况。 首先,Spring通过Bean的单例或多例模式来管理对象。在Web应用中,大部分服务类通常设置为单例模式...

    Spring事务流程图

    Spring事务管理是Spring框架的核心特性之一,主要用于处理应用程序中的数据一致性问题。...通过理解和使用Spring事务流程图,我们可以更好地设计和优化我们的应用程序,确保在多线程环境下的数据一致性。

    使用Spring实现读写分离(MySQL实现主从复制)

    2. **DynamicDataSourceHolder类**:使用`ThreadLocal`存储当前线程的数据源标识,确保线程安全。 3. **DataSourceAspect类**:定义一个AOP切面,在进入业务逻辑方法前根据方法名前缀判断应使用读库还是写库,并在...

    springsecurity原理流程图.pdf

    认证成功后,Spring Security会将认证信息存储在session中,并通过调用sessionStrategy.onAuthentication方法来处理与session相关的操作。 b. 最终,会执行successfulAuthentication方法,该方法可以被子类覆盖以...

    spring quartz 集群模式

    这里`myTargetObject`是一个bean引用,表示执行任务的目标对象,`executeTask`是该对象上的执行方法,`concurrent`属性决定是否允许多线程并发执行。 总结来说,Spring与Quartz的集群模式是通过共享数据库存储和...

    Excel导入Oracle数据库关键代码

    同时,根据数据量大小,可以考虑是否采用多线程并行处理。 8. **扩展性**:描述中提到代码有很好的扩展性,意味着可能设计了灵活的接口或抽象类,方便添加新的数据处理逻辑,比如支持其他类型的数据库,或者增加...

    初探spring aop内部实现 java

    在Spring中,DataSource是用于存储和管理数据库连接的核心组件。Spring提供了多种DataSource实现,如BasicDataSource、SingleConnectionDataSource等。以AbstractDataSource为基础,这些DataSource都实现了...

    购物网站源码 Java+mysql数据库源代码

    开发者需要熟悉Java语法、异常处理、多线程、IO流、集合框架等核心概念。 MySQL作为关系型数据库管理系统,用于存储和管理购物网站的数据,如商品信息、用户账户、订单等。开发者需要掌握SQL语句,包括DML(数据...

    Redis+mysql整合spring的Demo

    综上所述,"Redis+mysql整合spring的Demo"项目涵盖了数据库集成、缓存策略、事务管理等多个核心知识点,是学习和实践数据存储和高性能应用的好资源。通过对这些内容的理解和实践,开发者可以更好地应对复杂的企业级...

    java备份还原数据库

    - 如果需要同时备份多个数据库,可以使用Java的多线程技术,例如`Thread`或`ExecutorService`。 9. **自动化** - 利用Java的定时任务库(如Quartz或Spring Scheduler)实现备份的自动化。 10. **性能优化** - ...

    spring-jms入门

    - **MessageListenerContainer**:通过实现`MessageListener`接口,Spring容器会自动启动监听线程,接收到消息后调用监听器方法。 - **JmsTemplate.receive()**:阻塞式接收,调用后会等待直到有消息到达。 **7. ...

    springboot实现将Excel导入数据库

    在实际项目中,我们还可能需要考虑错误处理、日志记录、多线程处理大文件等复杂情况。此外,为了提高效率,可以使用Spring Batch进行批量数据处理,或者使用Spring Data JPA的Repository来简化数据库操作。 总之,...

Global site tag (gtag.js) - Google Analytics