JDBC高级(1)事务

一、JDBC事务管理

事务的描述:

事务指的是逻辑上的一组操作,组成这组操作各个逻辑单元要么全都成功,要么全都失败。
为什么使用事务?
例如:下面的代码:

public void shiwu(){
		Connection conn = null;//连接
		PreparedStatement pstam = null;//执行者
		ResultSet rs = null;//结果集
		
		try {
			conn = JDBCUtils.buildConnection();//获取连接
			//sql语句
			String sql = "update yinhang set price = price+? where id=?";
			//预处理
			pstam = conn.prepareStatement(sql);
			//赋值
			pstam.setInt(1, -100);
			pstam.setInt(2, 1);
			//执行语句
			int i = pstam.executeUpdate();
			
			//异常发生
			int a = 1/0;
			
			pstam.setInt(1, +100);
			pstam.setInt(2, 2);
			int i2 = pstam.executeUpdate();
			if (i == i2) {
				System.out.println("转账成功");
			}	
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			JDBCUtils.release(conn, pstam);
		}	
	}

注意:假如这是一个银行存取款,在这个时候异常发生,会导致前一个人的钱已经扣除,后一个人的钱还没有加上,导致数据丢失,存在数据的不完整性。
在这种情况下,就需要使用事务。

在下列代码就对上述代码进行了修正

@Test
	public void shiwu(){
		Connection conn = null;//连接
		PreparedStatement pstam = null;//执行者
		ResultSet rs = null;//结果集
		
		try {
			conn = JDBCUtils.buildConnection();//获取连接
			//开启事务
			conn.setAutoCommit(false);
			//sql语句
			String sql = "update yinhang set price = price+? where id=?";
			//预处理
			pstam = conn.prepareStatement(sql);
			//赋值
			pstam.setInt(1, -100);
			pstam.setInt(2, 1);
			//执行语句
			int i = pstam.executeUpdate();
			
			//异常发生
			int a = 1/0;
			
			pstam.setInt(1, +100);
			pstam.setInt(2, 2);
			int i2 = pstam.executeUpdate();
			if (i == i2) {
				System.out.println("转账成功");
			}
			
			//提交
			conn.commit();
			
		} catch (Exception e) {
			e.printStackTrace();
			try {
				//回滚
				conn.rollback();
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
		}finally {
			JDBCUtils.release(conn, pstam);
		}
	}

注意:事务是Connection的方法,setAutoCommit()方法:将此连接的自动提交模式设置为给定状态。如果连接处于自动提交模式下,则它的所有 SQL 语句将被执行并作为单个事务提交。所以参数需要写成false。

二、Druid实现连接池

可以与Spring框架进行快速的整合:相当于一个容器
代码实现:
配置文件:

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///db1
username=root
password=123456

工具类:这个工具类在jdbc的使用中可见
测试类:

@Test
	public void druidTest(){

		Connection conn = null;
		PreparedStatement pstam = null;
		ResultSet rs = null;
		
		try {
			//创建Properties对象
			Properties properties = new Properties();
			//读取文件
			properties.load(new FileInputStream("src/druid.properties"));
			//获取连接池对象
			DataSource createDataSource = DruidDataSourceFactory.createDataSource(properties);
			//建立连接
			conn = createDataSource.getConnection();
			String sql = "insert into yinhang values (null,?,?)";
			pstam = conn.prepareStatement(sql);
			pstam.setString(1, "张飞");
			pstam.setInt(2, 1000);
			int i = pstam.executeUpdate();
			if (i>0) {
				System.out.println("插入成功");
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			JDBCUtils.release(conn, pstam);
		}

	}

注意:

  • 在上述代码中依然需要释放Connection,虽然调用的依然是.close()方法,但其实被DruidDataSource包装,当释放时会归还到连接池中,而不是释放
  • Druid配置步骤:先拿连接池,再建立连接
  • DruidDataSourceFactory.creatDataSource(properties对象):直接拿到数据库连接

三、c3p0实现连接池

注意:c3p0实现了一个功能,就是在生成连接池的时候,如果没有指定xml文件,将会自动的去src目录下查找一个名字为c3p0-config.xml的文件。所以在下列的代码中看不到任何加载驱动和连接数据库的代码。
连接池不能一直创建,否则就会造成资源的浪费
实现:
c3p0-config.xm:

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
	<default-config>
		<property name="driverClass">com.mysql.jdbc.Driver</property>
		<property name="jdbcUrl">jdbc:mysql:///db1</property>
		<property name="user">root</property>
		<property name="password">123456</property>
		
		<property name="initialPoolSize">5</property>
		<property name="minPoolSize">5</property>
		<property name="maxPoolSize">20</property>
	</default-config> 
	
</c3p0-config>

工具类JDBCUtils2

public class JDBCUtils2 {
	
	private static final ComboPooledDataSource source = new ComboPooledDataSource();
	
	//建立连接
	public static Connection getConnection() throws SQLException{
		return source.getConnection();
	}

	//获取连接池
	public static DataSource getDataSource(){
		return source;
	}
	
	
	//释放资源(这是对于查的资源释放)
	public static void release(Connection conn,Statement stat,ResultSet rs){
		if (conn != null) {
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			conn = null;
		}
		
		if (stat != null) {
			try {
				stat.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			stat = null;
		}
		
		if (rs != null) {
			try {
				rs.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			rs = null;
		}
	}
	
	//这里使用了方法的重载,来实现对增删改进行资源的释放
	public static void release(Connection conn,Statement stat){
		if (conn != null) {
			try {
				//这里虽然依然是close,但是被装饰了,此时调用的close方法将会将连接返回到连接池
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			conn = null;
		}
		
		if (stat != null) {
			try {
				stat.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			stat = null;
		}
	}
}

注意:在这个工具类中需要着重的理解一下问什么使用close()方法来返回连接,在代码的注释中有解释

测试类C3p0Demo :

public class C3p0Demo {
	
	@Test
	public void c3p0Test(){
		Connection conn = null;
		PreparedStatement prstm = null;
		ResultSet rs = null;
		
		try {
			//调用工具类,从连接池中获取连接
			conn = JDBCUtils2.getConnection();
			//写sql语句
			String sql = "insert into yinhang values(null,?,?)";
			//预编译
			prstm = conn.prepareStatement(sql);
			//赋值
			prstm.setString(1, "小乔");
			prstm.setInt(2, 2000);
			//执行
			int i = prstm.executeUpdate();
			if (i > 0) {
				System.out.println("插入成功");
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			//返回连接
			JDBCUtils.release(conn, prstm);
		}
	}

}

未完待续,剩下内容明天更。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值