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