Java for Web学习笔记(一零五):Spring框架中使用JPA(5)Isolation和C3P0(上)

何为事务的isolation

isolation对于数据的一致性很重要。网上有很多介绍,推荐阅读:

一般而言,如果使用READ_UNCOMMITTED,这适合于只读的表格,大家读取同一条目无需等待;但是对于读写的表格,如果我们读取某个数据,然后修改并写入,就需要使用READ_COMMITTED、REPEATABLE_READ或者SERIALIZABLE,它们会将读操作放入到事务中,如果使用READ_UNCOMMITTED,就会有数据混乱(脏数据)的风险。其中SERIALIZABLE慎用,很容易会造成死锁。具体采用哪种,根据需求,下面是javadoc的介绍:

Connection.TRANSACTION_READ_UNCOMMITTED
A constant indicating that dirty reads, non-repeatable reads and phantom reads can occur. This level allows a row changed by one transaction to be read by another transaction before any changes in that row have been committed (a "dirty read"). If any of the changes are rolled back, the second transaction will have retrieved an invalid row.
Connection.TRANSACTION_READ_COMMITTED
A constant indicating that dirty reads are prevented; non-repeatable reads and phantom reads can occur. This level only prohibits a transaction from reading a row with uncommitted changes in it.
Connection.TRANSACTION_REPEATABLE_READ
A constant indicating that dirty reads and non-repeatable reads are prevented; phantom reads can occur. This level prohibits a transaction from reading a row with uncommitted changes in it, and it also prohibits the situation where one transaction reads a row, a second transaction alters the row, and the first transaction rereads the row, getting different values the second time (a "non-repeatable read").
Connection.TRANSACTION_SERIALIZABLE
A constant indicating that dirty reads, non-repeatable reads and phantom reads are prevented. This level includes the prohibitions in TRANSACTION_REPEATABLE_READ and further prohibits the situation where one transaction reads all rows that satisfy a WHERE condition, a second transaction inserts a row that satisfies that WHERE condition, and the first transaction rereads for the same condition, retrieving the additional "phantom" row in the second read.

数据源的isolaction设置

tomcat数据源

isolation是针对数据源进行设置的。如果我们采用tomcat的数据源,只需进行全局配置。

<Resource name="jdbc/learnTest" type="javax.sql.DataSource"
     maxActive="20" maxIdle="5" maxWait="10000"
     username="test" password="test123456"
     driverClassName="com.mysql.jdbc.Driver"
     defaultTransactionIsolation="READ_COMMITTED"
     url="jdbc:mysql://191.8.1.107:3306/test" />

C3P0数据源

一般情况,我们推荐使用tomcat设置数据源的方式,因为在war包无需考虑封装mysql的相关包,也无需在卸装是谨慎处理数据源的关闭。但是基于某些原因,例如在war启动后,动态获取数据库的配置信息,这时就很难使用静态的tomcat数据源的配置。采用的提供数据库连接管理池为C3P0,我们之前也在代码中介绍过,再次借isolation的机会再次详细说明。

如何创建C3P0数据源并安全关闭
为来方便使用,我们使用C3P0Utils来实现数据源的创建,并提供destory()方式,供war关闭时安全地关闭数据源。

public class C3P0Utils {
	private static final Logger logger = LogManager.getLogger();	
	private static final Map<String,ComboPooledDataSource> dataSourceDb = new HashMap<>();
	
	public static ComboPooledDataSource open (String name,String jdbcUrl,String user, String pw, 
			int minPoolSize,int maxPoolSize,int poolIncrement) throws Exception{
		if(dataSourceDb.containsKey(name))
			throw new Exception("数据源已经存在,请不要重复创建。");
		
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setDriverClass("com.mysql.jdbc.Driver");
		dataSource.setJdbcUrl(jdbcUrl + "?useSSL=true&useUnicode=true&characterEncoding=utf-8&autoReconnect=true");
		dataSource.setUser(user);
		dataSource.setPassword(pw);		
		dataSource.setMinPoolSize(minPoolSize);
		dataSource.setAcquireIncrement(poolIncrement);
		dataSource.setMaxPoolSize(maxPoolSize);
		dataSource.setInitialPoolSize(minPoolSize);
		dataSource.setMaxIdleTime(30);		
		dataSource.setIdleConnectionTestPeriod(30);
		//下面这句和设置Isolation有关,我们将后面介绍
		dataSource.setConnectionCustomizerClassName("com.wei.utils.MyConnectionCustomizer");
		/* 检查数据源是否有效。C3P0不会在创建dataSource时就去连接,而在第一次连接请求时进行。
		 * 一方面会增加第一个用户请求的处理时间,影响第一个用户的体验;
		 * 另一方面如果密码错误或者地址不可访问,我们需要在项目部署的第一时间知道是否部署正确,而不是等到业务来了才发现。*/
		try{
			Connection conn = dataSource.getConnection();
			conn.close();
		}catch(Exception e){
			DataSources.destroy( dataSource);  // or dataSource.close()
			throw new Exception("DataSource  open error :" + e.toString());			
		}
		
		dataSourceDb.put(name, dataSource);		
		logger.info("[INIT] Opened DataSource '{}' ... [OK]",name);
		return dataSource;
	}

	
	/**
	 * 在项目结束的时候,应释放所有资源,应调用本方法。建议阅读C3P0官网。
	 */
	public static void destroy(){
		logger.info("[CLOSE] close DataSource...");
		
		Iterator<Map.Entry<String,ComboPooledDataSource>> iter = dataSourceDb.entrySet().iterator();
		while (iter.hasNext()) {
			Map.Entry<String,ComboPooledDataSource> entry =  iter.next();
			ComboPooledDataSource dataSource = (ComboPooledDataSource)entry.getValue();
			dataSource.close();
		}
		dataSourceDb.clear();
		
		com.mysql.jdbc.AbandonedConnectionCleanupThread.checkedShutdown();
		
		Enumeration<java.sql.Driver> drivers = DriverManager.getDrivers();
		while(drivers.hasMoreElements()) {
			try {				
				Driver driver = drivers.nextElement();
				DriverManager.deregisterDriver(driver);
			} catch (SQLException e) {
				logger.error("C3M0 destroy error : {}", e.toString());
			}
		}
	}	
}
在上下文配置中:

@Bean 
public DataSource springJpaDataSource() throws Exception{
    return C3P0Utils.open("learnTest","jdbc:mysql://192.168.1.2:3306/test","test","test123456",2, 200, 2);
}

设置C3P0的isolation等级
如果采用C3P0,稍微要复杂一点。C3P0的缺省可能是NONE,或者是READ_UNCOMMITTED,这个我未确定。可以通过定制ConnectionCustomizer接口来实现:

public class MyConnectionCustomizer implements ConnectionCustomizer{ 
    @Override
    public void onAcquire( Connection c, String pdsIdt ) {
        // override the default transaction isolation of newly acquired Connections 
        c.setTransactionIsolation( Connection.TRANSACTION_SERIALIZABLE);
    }
    @Override
    public void onDestroy( Connection c, String pdsIdt ) {
    }
    @Override
    public void onCheckOut( Connection c, String pdsIdt ) {
    }
    @Override
    public void onCheckIn( Connection c, String pdsIdt ) {
    }
}
在创建c3p0数据源时,需要设置改定制的连接接口。

dataSource.setConnectionCustomizerClassName("com.wei.utils.MyConnectionCustomizer");
相关链接: 我的Professional Java for Web Applications相关文章

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Java Web高级编程是指在Java平台下进行高级Web开发的技术和方法。其涵盖了Websockets、Spring Framework和JPA技术。 Websockets是一种在客户端和服务器之间实现双向通信的技术。相对于传统的HTTP请求-响应模式,Websockets能够实现实时的双向通信,使得服务器能够主动向客户端推送消息,而不需要客户端发起请求。它能够提供更好的实时性和性能,适用于实时聊天、在线游戏、协同编辑等场景。 Spring Framework是一个开源的Java应用程序框架,广泛用于企业级Java应用的开发。它提供了一套完整的解决方案,包括IoC容器、AOP、数据访问、Web开发、消息队列、事务管理等模块。在Java Web高级编程Spring Framework可以用来实现MVC架构,处理请求和响应,管理业务逻辑和数据访问层的交互。 JPAJava Persistence API)是Java EE的一部分,用于将Java对象持久化到关系型数据库。它提供了一些注解和API,使得开发者可以通过对象操作来进行数据库的访问和操作,而不需要直接编写SQL语句。JPA简化了数据库操作的过程,提高了开发效率,并且保持了与数据库的解耦。在Java Web高级编程JPA可以与Spring Framework集成,实现ORM(Object-Relational Mapping)的功能,简化数据访问层的开发。 总的来说,Java Web高级编程涵盖了Websockets、Spring Framework和JPA技术,通过使用这些技术,开发者可以实现高效的Web应用程序,提供实时的双向通信,简化开发过程,并且保持与数据库的解耦。这些技术在现代的Web开发得到广泛应用,可以满足各种复杂的业务需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值