数据库_jdbc_事务1


JdbcUtils_bad位于utils包

package cn.itcast.utils;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
public class JdbcUtils_bad {
	//一个成员记住连接池
	private static DataSource ds;	
	//静态代码块初始化一个DBCP连接池
	static{
		   try{
            Properties prop = new Properties();
            InputStream in = JdbcUtils_bad.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
            prop.load(in);
            BasicDataSourceFactory factory = new BasicDataSourceFactory();
            ds = factory.createDataSource(prop);
         }catch (Exception e) {
            throw new ExceptionInInitializerError(e);
         }
   }
   //如果关系到事务!不能将连接池传递给QueryRunner构造函数,
   //而是在它update 或query时传个连接!
   public static Connection getConnection() throws SQLException {
      return ds.getConnection();
   }
}


AccountDao_bad位于dao包

package cn.itcast.dao;
import java.sql.Connection;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import cn.itcast.domain.Account;
//DAO内部维护一个连接,构造时需传入一个连接,
//并使用该连接进行CRUD(不优雅,实际开发中不使用!)
public class AccountDao_bad {
	private Connection conn;
	//有参的构造函数最好配个无参的构造函数
	public AccountDao_bad() {
		super();
	}
	//不优雅!构造AccountDao的时候还要接收一个连接!所有CRUD操作都是在此连接上完成!
	//构造AccountDao的时候就接收一个连接!所有CRUD操作都是在此连接上完成!
	public AccountDao_bad(Connection conn) {
		this.conn=conn;
	}
	public void update(Account a){
		try{
			//因为事务如转帐,所以new QueryRunner的时候不能传它DataSource,
			//而要自己控制事务提交和关闭连接!
			QueryRunner runner = new QueryRunner();
			String sql = "update account set money=? where id=?";
			Object params[] = {a.getMoney(),a.getId()};
			//因为是处理事务,所以要自己控制连接的开启事务,提交事务
			runner.update(conn,sql, params);
		}catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	public Account find(int id){
		try{
			//因为事务如转帐,所以new QueryRunner的时候不能传它DataSource
			//而要自己控制事务提交和关闭连接!
			QueryRunner runner = new QueryRunner();
			String sql = "select * from account where id=?";
			//因为是处理事务,所以要自己控制连接的开启事务,提交事务
			return (Account) runner.query(conn,sql, id, new BeanHandler(Account.class));
		}catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
}


/*
//理论可行,开发不能用!DAO层不能处理业务,只提供CRUD
	//从a--->b帐户转100元,实际开发不能用!因为违背了3层架构DAO层应与Service解耦
	public void transfer() throws SQLException{
		Connection conn = null;
		try{
			
			conn = JdbcUtils.getConnection();
         //在连接上开启事务
         conn.setAutoCommit(false);
         //因为转帐,所以new QueryRunner的时候不能传它DataSource,
         //而是要自己事务提交后才关闭连接!
         QueryRunner runner = new QueryRunner();
         String sql1 = "update account set money=money-100 where name='aaa'";
         runner.update(conn,sql1);
         String sql2 = "update account set money=money+100 where name='bbb'";
         runner.update(conn,sql2);
         //提交事务
         conn.commit();
      }finally{
         //最后将连接还给连接池
         if(conn!=null){
            conn.close();
         }
      }
   }
*/


AccountService_bad位于service包

package cn.itcast.service;
import java.sql.Connection;
import java.sql.SQLException;
import org.junit.Test;
import cn.itcast.dao.AccountDao_bad;
import cn.itcast.domain.Account;
import cn.itcast.utils.JdbcUtils_bad;
public class AccountService_bad {
	/*这种管理事务的方法是:(不优雅,实际开发中不使用!)
	 * 1,Service负责提供一个连接(从连接池中获取)
	 * 2,Service负责开启这个连接上的事务
	 * 3,使用Dao完成业务的时候,将该连接传给Dao(作为构造时参数传进去)
	 * 		DAO内部维护一个连接,构造时需传入一个连接接收,
	 * 		并使用该连接进行CRUD.
	 * 4,Service控制该连接提交事务!
	 */
	@Test
	public void test() throws SQLException{
		transfer1(1,2,50);
	}
	//业务之一:转帐功能
	//实际开发中,这种也不实用,也不优雅!哪有构造DAO的时候还传个连接进去的!
	//而实用的是用Spring或ThreadLocal绑定连接
	public void transfer1(int sourceid,int targetid,float money) throws SQLException{
		Connection conn = null;
		try {
			//自己从池中获得连接(记得自己释放)
			conn=JdbcUtils_bad.getConnection();
			//在连接上开启事务!
			conn.setAutoCommit(false);
			//重点在这句,指定连接conn传给DAO,让所有CRUD在此连接上完成!
         //DAO内部维护一个连接,构造时需传入一个连接,
         //并使用该连接进行CRUD(不优雅,实际开发中不使用!)
         AccountDao_bad dao=new AccountDao_bad(conn);
         //使用指定的连接(已开启事务的连接)处理下面4条SQL!
         Account a = dao.find(sourceid);   //select语句1
         Account b = dao.find(targetid);   //select语句2
         a.setMoney(a.getMoney()-money);  
         b.setMoney(b.getMoney()+money);   
         dao.update(a); //update语句1
         dao.update(b);//update语句2
         conn.commit();
      } finally{
         //最后将连接还给连接池
         if(conn!=null) conn.close();
      }
   }
}


用到的第3方jar包

mysql-connector-java-5.0.8-bin.jar
commons-dbcp-1.2.2.jar
commons-pool.jar
commons-dbutils-1.2.jar

mysql -uroot -proot
set character_set_client=gb2312;
set character_set_results=gb2312;
use day17;
create table account(
	id int primary key auto_increment,
	name varchar(40),
	money float
)character set utf8 collate utf8_general_ci;
insert into account(name,money) values('林黛玉',1000);
insert into account(name,money) values('薛宝钗',1000);
insert into account(name,money) values('史湘云',1000); 


dbcpconfig.properties位于src目录

#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/day17
username=root
password=root
#<!-- 初始化连接 -->
initialSize=10
#最大连接数量
maxActive=50
#<!-- 最大空闲连接 -->
maxIdle=20
#<!-- 最小空闲连接 -->
minIdle=5
#<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 即等1分钟后仍没连接,这时才告诉人家,呆会再来,暂无连接! -->
maxWait=60000
#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;] 
#注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。
connectionProperties=useUnicode=true;characterEncoding=utf8
#指定由连接池所创建的连接的自动提交(auto-commit)状态。
defaultAutoCommit=true
#driver default 指定由连接池所创建的连接的只读(read-only)状态。
#如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)
defaultReadOnly=
#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_COMMITTED










你可能感兴趣的:(数据库,jdbc,事务)