demo1_JDBC演示事务
package cn.itcast.demo; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import cn.itcast.exception.DaoException; import cn.itcast.utils.JdbcUtils; public class demo1 { public static void main(String[] args) { method1(); } private static void method1() { /*方法说明:JDBC演示事务!day16库,表account(id,name,money) *id为1的帐户向id为2的帐户转100元*/ //SQL更新模板代码(sql_u) Connection conn = null; PreparedStatement st = null; ResultSet rs = null; try { conn = JdbcUtils.getConnection(); //因转帐,获得连接后,开启事务 conn.setAutoCommit(false);//相当于sql中start transaction String sql = "update account set money=money-100 where id=?"; st = conn.prepareStatement(sql); st.setInt(1, 1); st.executeUpdate(); //再发第2条sql sql = "update account set money=money+100 where id=?"; st = conn.prepareStatement(sql); st.setInt(1, 2); st.executeUpdate(); //出现异常 int x=1/0; //最后提交事务 conn.commit(); } catch (Exception e) { throw new DaoException(e); } finally { JdbcUtils.release(conn, st, rs); } } }
demo2_JDBC演示事务回滚点
package cn.itcast.demo; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Savepoint; import cn.itcast.exception.DaoException; import cn.itcast.utils.JdbcUtils; public class demo2 { public static void main(String[] args) throws SQLException { method1(); } private static void method1() throws SQLException { /*方法说明:day16库,表account(id,name,money) *id为1的帐户向id为2的帐户转100元 *id为1的帐户向id为3的帐户转100元 *事务回滚点*/ //SQL更新模板代码(sql_u) Connection conn = null; PreparedStatement st = null; ResultSet rs = null; //回滚点! Savepoint sp=null; try { //mysql默认连接的隔离级别:repeatable read(可重复读,即每次读的都一样) //属第3种隔离级别,可以预防脏读和不可重复读! conn = JdbcUtils.getConnection(); //因转帐,获得连接后,开启事务 conn.setAutoCommit(false);//相当于sql中start transaction String sql = "update account set money=money-100 where id=?"; st = conn.prepareStatement(sql); st.setInt(1, 1); st.executeUpdate(); //再发第2条sql sql = "update account set money=money+100 where id=?"; st = conn.prepareStatement(sql); st.setInt(1, 2); st.executeUpdate(); //设置回滚点,即无论a向c转帐是否成功都尽量确保a向b转帐是成功的!! sp=conn.setSavepoint(); //再发第3条sql sql = "update account set money=money-100 where id=?"; st = conn.prepareStatement(sql); st.setInt(1, 1); st.executeUpdate(); //再发第4条sql sql = "update account set money=money+100 where id=?"; st = conn.prepareStatement(sql); st.setInt(1, 3); st.executeUpdate(); //出现异常 int x=1/0; //最后提交事务 conn.commit(); } catch (Exception e) { e.printStackTrace(); //出现异常后,手动回滚到指定回滚点,尽量确保a向b转帐是成功的! conn.rollback(sp); //仅仅是回滚是没用的,必须还要提交事务! conn.commit(); //手动回滚后,一定要记得提交事务 } finally { JdbcUtils.release(conn, st, rs); } } }
demo3_JDBC演示事务隔离级别
package cn.itcast.demo; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Savepoint; import cn.itcast.exception.DaoException; import cn.itcast.utils.JdbcUtils; public class demo3 { public static void main(String[] args) throws SQLException { method1(); } private static void method1() throws SQLException { /*方法说明:day16库,表account(id,name,money) *简单演示jdbc设置隔离级别*/ //SQL更新模板代码(sql_u) Connection conn = null; PreparedStatement st = null; ResultSet rs = null; try { //mysql默认连接的隔离级别:repeatable read(可重复读,即每次读的都一样) //属第3种隔离级别,可以预防脏读和不可重复读! conn = JdbcUtils.getConnection(); //获得连接后,必须先设置好事务隔离级别,再开启事务 conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE); conn.setAutoCommit(false);//相当于sql中start transaction String sql = "select * from account"; st = conn.prepareStatement(sql); st.executeQuery(); //故意让线程等待10秒!另开一个doc窗口,开启事务进行操作!将出现等待的情况! Thread.sleep(1000*10); //最后才提交事务 conn.commit(); } catch (Exception e) { e.printStackTrace(); } finally { JdbcUtils.release(conn, st, rs); } } }
demo4_JDBC演示开源数据库连接池DBCP
package cn.itcast.demo; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import cn.itcast.utils.JdbcUtils_C3P0; import cn.itcast.utils.JdbcUtils_DBCP; public class demo4 { public static void main(String[] args) throws Exception { method1(); } private static void method2() throws SQLException { /*方法说明:演示开源数据库连接池DBCP的使用 *C3P0内部增强Connection的close方法使用的是动态代理拦截技术!*/ Connection conn = null; PreparedStatement st = null; ResultSet rs = null; try{ conn = JdbcUtils_C3P0.getConnection(); System.out.println(conn); //com.mchange.v2.c3p0.impl.NewProxyConnection@1049ddf System.out.println(conn.getClass().getName()); //com.mchange.v2.c3p0.impl.NewProxyConnection }finally{ JdbcUtils_DBCP.release(conn, st, rs); } } private static void method1() throws SQLException { /*方法说明:演示开源数据库连接池DBCP的使用 * DBCP内部增强Connection的close方法使用的是装饰模式!*/ Connection conn = null; PreparedStatement st = null; ResultSet rs = null; try{ conn = JdbcUtils_DBCP.getConnection(); System.out.println(conn); //jdbc:mysql://localhost:3306/day16, UserName=root@localhost, MySQL-AB JDBC Driver System.out.println(conn.getClass().getName()); //org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper }finally{ JdbcUtils_DBCP.release(conn, st, rs); } } } /* 使用动态代理重写连接池中的Connection proxyConn = (Connection) Proxy.newProxyInstance(this.getClass() .getClassLoader(), conn.getClass().getInterfaces(), new InvocationHandler() { //此处为内部类,当close方法被调用时将conn还回池中,其它方法直接执行 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getName().equals("close")) { pool.addLast(conn); return null; } return method.invoke(conn, args); } }); */
demo5_JDBC演示元数据
package cn.itcast.demo; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.ParameterMetaData; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import org.junit.Test; import cn.itcast.utils.JdbcUtils_C3P0; public class demo5 { @Test public void method1() throws SQLException { /*方法说明:演示获取数据库的元数据 */ Connection conn=JdbcUtils_C3P0.getConnection(); DatabaseMetaData meta=conn.getMetaData(); System.out.println("hello world"); System.out.println(meta.getDatabaseMajorVersion());//5 System.out.println(meta.getDatabaseMinorVersion());//0 System.out.println(meta.getDatabaseProductName());//MySQL System.out.println(meta.getDatabaseProductVersion());//5.0.22-community-nt System.out.println(meta.getDefaultTransactionIsolation());//2 System.out.println(meta.getDriverName());//MySQL-AB JDBC Driver System.out.println(meta.getDriverVersion());//mysql-connector-java-5.0.8 ( Revision: ${svn.Revision} ) System.out.println(meta.getDriverMajorVersion());//5 System.out.println(meta.getDriverMinorVersion());//0 } @Test public void method2() throws SQLException { /*方法说明:演示参数元数据*/ Connection conn=JdbcUtils_C3P0.getConnection(); String sql="insert into account(id,name,money) values(?,?,?)"; PreparedStatement st=conn.prepareStatement(sql); ParameterMetaData meta=st.getParameterMetaData(); System.out.println(meta.getParameterCount());//3,其他全部不支持 /*System.out.println(meta.getParameterClassName(1)); System.out.println(meta.getParameterMode(1)); 注意:mysql驱动不支持:参数元数据的方法:获取参数类型! System.out.println(meta.getParameterType(1)); System.out.println(meta.getParameterTypeName(1)); System.out.println(meta.getPrecision(1));*/ } @Test public void method3() throws SQLException { /*方法说明:演示结果集元数据*/ Connection conn=JdbcUtils_C3P0.getConnection(); String sql="select * from account"; PreparedStatement st=conn.prepareStatement(sql); ResultSet rs=st.executeQuery(); ResultSetMetaData meta=rs.getMetaData(); System.out.println(meta.getTableName(2));//取表名:account表 System.out.println(meta.getCatalogName(1));//获取指定列的表目录名称:day16 System.out.println(meta.getColumnClassName(1));//java.lang.Integer 如果调用方法 ResultSet.getObject 从列中获取值,则返回构造其实例的 Java 类的完全限定名称。 System.out.println(meta.getColumnCount());//共有三个字段:即列数 3 返回此 ResultSet 对象中的列数。 System.out.println(meta.getColumnDisplaySize(1));//11 指示指定列的最大标准宽度,以字符为单位。 System.out.println(meta.getColumnLabel(1));//id 获取用于打印输出和显示的指定列的建议标题。 System.out.println(meta.getColumnName(1));//id 获取指定列的名称。 System.out.println(meta.getColumnType(1));//获取指定列的 SQL 类型。来自 java.sql.Types 的 SQL 类型 System.out.println(meta.getColumnTypeName(1));//INT 获取指定列的数据库特定的类型名称。 System.out.println(meta.getClass());//class com.mysql.jdbc.ResultSetMetaData System.out.println(meta.isReadOnly(1));//false } }package cn.itcast.demo; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.ParameterMetaData; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import org.junit.Test; import cn.itcast.utils.JdbcUtils_C3P0; public class demo5 { @Test public void method1() throws SQLException { /*方法说明:演示获取数据库的元数据 */ Connection conn=JdbcUtils_C3P0.getConnection(); DatabaseMetaData meta=conn.getMetaData(); System.out.println("hello world"); System.out.println(meta.getDatabaseMajorVersion());//5 System.out.println(meta.getDatabaseMinorVersion());//0 System.out.println(meta.getDatabaseProductName());//MySQL System.out.println(meta.getDatabaseProductVersion());//5.0.22-community-nt System.out.println(meta.getDefaultTransactionIsolation());//2 System.out.println(meta.getDriverName());//MySQL-AB JDBC Driver System.out.println(meta.getDriverVersion());//mysql-connector-java-5.0.8 ( Revision: ${svn.Revision} ) System.out.println(meta.getDriverMajorVersion());//5 System.out.println(meta.getDriverMinorVersion());//0 } @Test public void method2() throws SQLException { /*方法说明:演示参数元数据*/ Connection conn=JdbcUtils_C3P0.getConnection(); String sql="insert into account(id,name,money) values(?,?,?)"; PreparedStatement st=conn.prepareStatement(sql); ParameterMetaData meta=st.getParameterMetaData(); System.out.println(meta.getParameterCount());//3,其他全部不支持 /*System.out.println(meta.getParameterClassName(1)); System.out.println(meta.getParameterMode(1)); 注意:mysql驱动不支持:参数元数据的方法:获取参数类型! System.out.println(meta.getParameterType(1)); System.out.println(meta.getParameterTypeName(1)); System.out.println(meta.getPrecision(1));*/ } @Test public void method3() throws SQLException { /*方法说明:演示结果集元数据*/ Connection conn=JdbcUtils_C3P0.getConnection(); String sql="select * from account"; PreparedStatement st=conn.prepareStatement(sql); ResultSet rs=st.executeQuery(); ResultSetMetaData meta=rs.getMetaData(); System.out.println(meta.getTableName(2));//取表名:account表 System.out.println(meta.getCatalogName(1));//获取指定列的表目录名称:day16 System.out.println(meta.getColumnClassName(1));//java.lang.Integer 如果调用方法 ResultSet.getObject 从列中获取值,则返回构造其实例的 Java 类的完全限定名称。 System.out.println(meta.getColumnCount());//共有三个字段:即列数 3 返回此 ResultSet 对象中的列数。 System.out.println(meta.getColumnDisplaySize(1));//11 指示指定列的最大标准宽度,以字符为单位。 System.out.println(meta.getColumnLabel(1));//id 获取用于打印输出和显示的指定列的建议标题。 System.out.println(meta.getColumnName(1));//id 获取指定列的名称。 System.out.println(meta.getColumnType(1));//获取指定列的 SQL 类型。来自 java.sql.Types 的 SQL 类型 System.out.println(meta.getColumnTypeName(1));//INT 获取指定列的数据库特定的类型名称。 System.out.println(meta.getClass());//class com.mysql.jdbc.ResultSetMetaData System.out.println(meta.isReadOnly(1));//false } }
demo7_dao演示自定义JDBC框架
package cn.itcast.demo; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import org.junit.Test; import cn.itcast.domain.Account; import cn.itcast.utils.BeanHandler; import cn.itcast.utils.BeanListHandler; import cn.itcast.utils.IntegerHandler; import cn.itcast.utils.JdbcUtils; public class demo7_dao { //dao提供方法1:增强一个用户到数据库中! public void add(Account a){ //由于统一了update方法,所以只需要提供sql 和 Object[] params String sql="insert into account(name,money) values(?,?)"; Object[] params={a.getName(),a.getMoney()}; JdbcUtils.update(sql, params); } //模拟service层调用dao处理增加业务! @Test public void test_add(){ Account a=new Account(); a.setName("史湘云"); a.setMoney(1000); add(a); } //==================================== //dao提供方法2:从数据库中删除一个用户! public void delete(String id){ //由于统一了update方法,所以只需要提供sql 和 Object[] params String sql="delete from account where id=?"; Object[] params={id}; JdbcUtils.update(sql, params); } //模拟service层调用dao处理删除业务! @Test public void test_delete(){ String id="5"; delete(id); } //==================================== //dao提供方法3:从数据库中改(更新)一个用户! public void update(Account a){ //由于统一了update方法,所以只需要提供sql 和 Object[] params String sql="update account set name=?,money=? where id=?"; Object[] params={a.getName(),a.getMoney(),a.getId()}; JdbcUtils.update(sql, params); } //模拟service层调用dao处理更新业务! @Test public void test_update(){ Account a=new Account(); a.setName("史大姑娘"); a.setMoney(9000); a.setId(4); update(a); } //==================================== //dao提供方法4:从数据库中查找一个用户! public Account find(int id){ //由于统一了query方法,所以只需要提供sql 和 Object[] params 和接口ResultSetHandler的实现类 //由于是封装到bean里面,所以传需要bean.class字节码文件 String sql="select * from account where id=?"; Object[] params={id}; return (Account) JdbcUtils.query(sql, params,new BeanHandler(Account.class)); } //模拟service层调用dao处理查找一个用户业务! @Test public void test_findById(){ int id=3; Account a=find(id); System.out.println(a.getName()); } //==================================== //dao提供方法5:从数据库中查找所有用户并存入集合! public List<Account> getAll(){ //由于统一了query方法,所以只需要提供sql 和 Object[] params 和接口ResultSetHandler的实现类 //由于是封装到bean里面,所以传需要bean.class字节码文件 String sql="select * from account"; Object[] params={}; return (List<Account>) JdbcUtils.query(sql,params, new BeanListHandler(Account.class)); } //模拟service层调用dao处理查找所有用户并存入集合业务! @Test public void test_getAll(){ List list=getAll(); System.out.println(list.size());//3 System.out.println(list); //[cn.itcast.domain.Account@1bb60c3, //cn.itcast.domain.Account@cdb06e, //cn.itcast.domain.Account@1fa1bb6] } //==================================== //dao提供方法6:从数据库中统计总记录数! public Integer getCountNum(){ //由于统一了query方法,所以只需要提供sql 和 Object[] params 和接口ResultSetHandler的实现类 //将查询结果封装到Integer里面 String sql="select count(*) from account"; Object[] params={}; return (Integer) JdbcUtils.query(sql, params, new IntegerHandler()); } //模拟service层调用dao处理统计总记录数业务! @Test public void test_getCountNum(){ System.out.println(getCountNum());//4 } }
JDBCPool_Demo4演示理论上数据库连接池的实现
package cn.itcast.demo; import java.io.IOException; import java.io.PrintWriter; import java.sql.Array; import java.sql.Blob; import java.sql.CallableStatement; import java.sql.Clob; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.DriverManager; import java.sql.NClob; import java.sql.PreparedStatement; import java.sql.SQLClientInfoException; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.sql.SQLWarning; import java.sql.SQLXML; import java.sql.Savepoint; import java.sql.Statement; import java.sql.Struct; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.concurrent.Executor; import java.util.logging.Logger; import javax.sql.DataSource; //理论上数据库连接池的实现方式 ! public class JDBCPool_Demo4 implements DataSource { private static LinkedList list=new LinkedList<Connection>(); private static Properties pro=new Properties(); static{ //类加载时,就初始化一批连接! try { pro.load(JDBCPool_Demo4.class.getClassLoader().getResourceAsStream("db.properties")); Class.forName(pro.getProperty("driver")); //上面一句是注册驱动,之后就可以用驱动管理获取连接!批量 for (int i = 0; i < 10; i++) { Connection conn=DriverManager.getConnection(pro.getProperty("url"), pro.getProperty("user"), pro.getProperty("password")); list.add(conn); } } catch (Exception e) { throw new ExceptionInInitializerError(e); } } //覆写getConnection(),注意不能改变接口的声明!如:随意加static静态代该方法, conn.close()满足不了需求,因为close()默认是将连接释放了,而我们想将连接归还到连接池里面,即list集合中! /* 在实际开发,发现对象的方法满足不了开发需求时,有三种方式对其进行增强 * 1.写一个connecton子类,覆盖close方法,增强close方法 * 2.用包装设计模式(也称装饰模式) * 3.用动态代理 aop 面向切面编程 */ @Override public Connection getConnection() throws SQLException { /*方法说明:首先判断list是不是有Connection *然后还要必须保证conn.close()是归还到池子即list,而非释放掉 */ if (list.size()<=0) { throw new RuntimeException("暂无连接,一会再来"); } /*使用装饰模式,或动态代理,覆写conn.close方法 * 1,写个类,实现共同的接口 * 2,该类中定义一个成员,接收被装饰的对象 * 3,该类中定义一个带参数构造函数,传入的参数即为被装饰的对象 * 4,增强该增强的方法 * 5,不要增强的方法使用原来被装饰的对象完成 */ //千万不能用list.get(index);返回列表中指定位置的元素。 //只是返回对象的引用,而对象仍然在list集合里面!这就不是取出连接了! Connection conn=(Connection) list.removeFirst(); MyColl mycoll=new MyColl(conn); return mycoll; } @Override public Connection getConnection(String username, String password) throws SQLException { return null; } //使用内部类完成装饰 //包装设计模式(也称装饰模式)标准5步曲! //1.定义一个类(MyConnection),实现与被增强相同的接口(Connection) //2.在类中定义一个成员变量,记住被增强对象 //3.定义一个构造函数,接收被增强对象 //4.覆盖想增强的方法 //5.对于不想增强的方法,直接调用目标对象(被增强对象)的方法 class MyColl implements Connection{ private Connection conn; public MyColl(Connection conn) { super(); this.conn = conn; } public void close() throws SQLException { //增强想增强的方法! 覆写想增强的方法,即原来的满足不了需要的方法! list.add(this.conn); } /*其它不需要增强的方法使用构造时传进来的对象完成即可! * 由于方法实在太多,我们就使用开源组织提供的数据库连接池 * DBCP database Connection Pool * C3P0 */ @Override public boolean isWrapperFor(Class<?> iface) throws SQLException { return this.conn.isWrapperFor(iface); } @Override public <T> T unwrap(Class<T> iface) throws SQLException { return null; } @Override public void abort(Executor executor) throws SQLException { } @Override public void clearWarnings() throws SQLException { } @Override public void commit() throws SQLException { } @Override public Array createArrayOf(String typeName, Object[] elements) throws SQLException { return null; } @Override public Blob createBlob() throws SQLException { return null; } @Override public Clob createClob() throws SQLException { return null; } @Override public NClob createNClob() throws SQLException { return null; } @Override public SQLXML createSQLXML() throws SQLException { return null; } @Override public Statement createStatement() throws SQLException { return null; } @Override public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { return null; } @Override public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { return null; } @Override public Struct createStruct(String typeName, Object[] attributes) throws SQLException { return null; } @Override public boolean getAutoCommit() throws SQLException { return false; } @Override public String getCatalog() throws SQLException { return null; } @Override public Properties getClientInfo() throws SQLException { return null; } @Override public String getClientInfo(String name) throws SQLException { return null; } @Override public int getHoldability() throws SQLException { return 0; } @Override public DatabaseMetaData getMetaData() throws SQLException { return null; } @Override public int getNetworkTimeout() throws SQLException { return 0; } @Override public String getSchema() throws SQLException { return null; } @Override public int getTransactionIsolation() throws SQLException { return 0; } @Override public Map<String, Class<?>> getTypeMap() throws SQLException { return null; } @Override public SQLWarning getWarnings() throws SQLException { return null; } @Override public boolean isClosed() throws SQLException { return false; } @Override public boolean isReadOnly() throws SQLException { return false; } @Override public boolean isValid(int timeout) throws SQLException { return false; } @Override public String nativeSQL(String sql) throws SQLException { return null; } @Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { return null; } @Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { return null; } @Override public CallableStatement prepareCall(String sql) throws SQLException { return null; } @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { return null; } @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { return null; } @Override public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { return null; } @Override public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { return null; } @Override public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { return null; } @Override public PreparedStatement prepareStatement(String sql) throws SQLException { return null; } @Override public void releaseSavepoint(Savepoint savepoint) throws SQLException { } @Override public void rollback() throws SQLException { } @Override public void rollback(Savepoint savepoint) throws SQLException { } @Override public void setAutoCommit(boolean autoCommit) throws SQLException { } @Override public void setCatalog(String catalog) throws SQLException { } @Override public void setClientInfo(Properties properties) throws SQLClientInfoException { } @Override public void setClientInfo(String name, String value) throws SQLClientInfoException { } @Override public void setHoldability(int holdability) throws SQLException { } @Override public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { } @Override public void setReadOnly(boolean readOnly) throws SQLException { } @Override public Savepoint setSavepoint() throws SQLException { return null; } @Override public Savepoint setSavepoint(String name) throws SQLException { return null; } @Override public void setSchema(String schema) throws SQLException { } @Override public void setTransactionIsolation(int level) throws SQLException { } @Override public void setTypeMap(Map<String, Class<?>> map) throws SQLException { } } @Override public PrintWriter getLogWriter() throws SQLException { return null; } @Override public int getLoginTimeout() throws SQLException { return 0; } @Override public Logger getParentLogger() throws SQLFeatureNotSupportedException { return null; } @Override public void setLogWriter(PrintWriter out) throws SQLException { } @Override public void setLoginTimeout(int seconds) throws SQLException { } @Override public boolean isWrapperFor(Class<?> iface) throws SQLException { return false; } @Override public <T> T unwrap(Class<T> iface) throws SQLException { return null; } }
Account位于domain包
package cn.itcast.domain; public class Account { private int id; private String name; private double money; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getMoney() { return money; } public void setMoney(double money) { this.money = money; } }
DaoException位于exception包
package cn.itcast.exception; public class DaoException extends RuntimeException { public DaoException() { // TODO Auto-generated constructor stub } public DaoException(String message) { super(message); // TODO Auto-generated constructor stub } public DaoException(Throwable cause) { super(cause); // TODO Auto-generated constructor stub } public DaoException(String message, Throwable cause) { super(message, cause); // TODO Auto-generated constructor stub } }
package cn.itcast.utils; import java.sql.ResultSet; //由于拿到了结果集,不知如何处理,即不知道封装到哪儿去! //所以对外暴露一个接口,由调用该方法的人实现该接口,我再对其调用!策略模式! public interface ResultSetHandler { public Object handle(ResultSet rs); }
BeanHandler位于utils包
package cn.itcast.utils; import java.lang.reflect.Field; import java.sql.ResultSet; import java.sql.ResultSetMetaData; public class BeanHandler implements ResultSetHandler { //该类是将结果集封装到bean里面! //为了知道该结果集处理器是将结果封装到哪个bean里面, //所以需要一个构造函数接收该bean的字节码文件对象,并赋值给成员! private Class clazz; public BeanHandler(Class clazz) { super(); this.clazz = clazz; } public Object handle(ResultSet rs) { try { //首先分析结果集中有无数据 if (!rs.next()) { return null; } //然后就准备一个bean实例接收! Object bean=clazz.newInstance(); //获得结果集的元数据 ResultSetMetaData meta=rs.getMetaData(); //从元数据中获得字段的数目 int count=meta.getColumnCount(); //循环每个字段,将值赋予给bean对应的成员 for (int i = 0; i < count; i++) { //从元数据中获得字段的名称 String columnName=meta.getColumnName(i+1); //从结果集获得该字段的值 Object columnValue=rs.getObject(columnName); //通过反射,获取所有的类成员 Field field=bean.getClass().getDeclaredField(columnName); //打开类成员的暴力访问 field.setAccessible(true); //为bean对象的成员赋值 field.set(bean, columnValue); } //循环完毕即为bean对象的每个成员赋值! return bean; } catch (Exception e) { throw new RuntimeException(); } } }
BeanListHandler位于utils包
package cn.itcast.utils; import java.lang.reflect.Field; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.util.ArrayList; import java.util.List; public class BeanListHandler implements ResultSetHandler { //该类是将结果集封装到bean里面,然后把所有的bean加到list集合里面! //为了知道该结果集处理器是将结果封装到哪个bean里面, //所以需要一个构造函数接收该bean的字节码文件对象,并赋值给成员! private Class clazz; public BeanListHandler(Class clazz) { super(); this.clazz = clazz; } public Object handle(ResultSet rs) { //先准备一个集合 List list=new ArrayList(); try { //首先分析结果集中有无数据 if (!rs.next()) { return null; } //然后遍历每一条记录,将每一条记录封装到一个bean里面,并且bean添加到list while (rs.next()) { //准备一个bean实例接收一条记录! Object bean=clazz.newInstance(); //获得结果集的元数据 ResultSetMetaData meta=rs.getMetaData(); //从元数据中获得字段的数目 int count=meta.getColumnCount(); //循环每个字段,将值赋予给bean对应的成员 for (int i = 0; i < count; i++) { //从元数据中获得字段的名称 String columnName=meta.getColumnName(i+1); //从结果集获得该字段的值 Object columnValue=rs.getObject(columnName); //通过反射,获取所有的类成员 Field field=bean.getClass().getDeclaredField(columnName); //打开类成员的暴力访问 field.setAccessible(true); //为bean对象的成员赋值 field.set(bean, columnValue); } //循环完毕即为bean对象的每个成员赋值! //将封装好了一条记录的bean加到list中! list.add(bean); } //最后,遍历完所有记录后,返回list return list; } catch (Exception e) { throw new RuntimeException(); } } }
IntegerHandler位于utils包
package cn.itcast.utils; import java.lang.reflect.Field; import java.sql.ResultSet; import java.sql.ResultSetMetaData; public class IntegerHandler implements ResultSetHandler { //该类是将结果集封装到Integer里面! public Object handle(ResultSet rs) { try { //首先分析结果集中有无数据 if (!rs.next()) { return 0; } //然后才返回统计数目:如select count(*) from 表名 return rs.getInt(1); } catch (Exception e) { throw new RuntimeException(); } } }
JdbcUtils_C3P0位于utils包
package cn.itcast.utils; import java.io.InputStream; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Properties; import javax.sql.DataSource; import org.apache.commons.dbcp.BasicDataSourceFactory; import com.mchange.v2.c3p0.ComboPooledDataSource; /**演示开源数据库连接池C3P0的使用 C3P0内部增强Connection的close方法使用的是动态代理! 1,导入两个jar包到工程下的lib目录,变成奶瓶 c3p0-0.9.2-pre1.jar mchange-commons-0.2.jar 如果使用oralce数据库,还要c3p0-oracle-thin-extras-0.9.2-pre1.jar 2,设置src下的c3p0-config.xml配置文件信息如库名! 3,新建一个工具类如:JdbcUtils_C3P0 4,定义成员记住C3P0创建出来的数据源(即连接池) 5,静态代码块中用创建数据源(即连接池) 6,定义获取连接的方法 7,定义释放连接的方法 */ public class JdbcUtils_C3P0 { //定义成员记住DBCP创建出来的数据源(即连接池) private static DataSource ds; static{ try { //C3P0连接池--固定代码: //new ComboPooledDataSource创建数据源(即连接池) //用类成员ds记住根据参数(空参表示使用c3p0默认的配置)创建出来的连接池! //new的时候不指定参数,则使用的是default配置!否则使用指定名称配置, //如"mysql",具体名称见c3p0-config.xml ds=new ComboPooledDataSource(); //ds=new ComboPooledDataSource("mysql"); //然后自动搜索类目录下名为:c3p0-config.xml的文件进行初始化! } catch (Exception e) { throw new ExceptionInInitializerError(e); } } //方法1:获取使用了动态代理的连接 public static Connection getConnection() throws SQLException{ //C3P0在生成连接的时候已经使用动态代理拦截Connection名为close的方法, //并覆写了close方法,即归还到数据源(即连接池) //返回的是NewProxyConnection return ds.getConnection(); } //方法2:释放连接 public static void release(Connection conn,Statement st,ResultSet rs){ if (conn!=null) { try { conn.close(); }catch (Exception e) { //只能记录!一旦抛出,后面的2条if代码就无法执行了 e.printStackTrace(); } conn=null; } if (st!=null) { try { st.close(); }catch (Exception e) { //只能记录!一旦抛出,后面的1条if代码就无法执行了 e.printStackTrace(); } st=null; } if (rs!=null) { try { rs.close(); }catch (Exception e) { e.printStackTrace(); } rs=null; } } }
JdbcUtils_DBCP位于utils包
package cn.itcast.utils; import java.io.InputStream; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Properties; import javax.sql.DataSource; import org.apache.commons.dbcp.BasicDataSourceFactory; /**演示开源数据库连接池DBCP的使用 DBCP内部增强Connection的close方法使用的是装饰模式! 1,导入两个jar包到工程下的lib目录,变成奶瓶 commons-dbcp-1.2.2.jar commons-pool.jar 2,设置src下的dbcpconfig.properties配置文件信息如库名! 3,新建一个工具类如:JdbcUtils_DBCP 4,定义成员记住DBCP创建出来的数据源(即连接池) 5,静态代码块中用BasicDataSourceFactory创建数据源(即连接池) 6,定义获取连接的方法 7,定义释放连接的方法 */ public class JdbcUtils_DBCP { //定义成员记住DBCP创建出来的数据源(即连接池) private static DataSource ds; static{ try { String pro_name="dbcpconfig.properties"; InputStream in=JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream(pro_name); Properties pro = new Properties(); pro.load(in); //DBCP连接池--固定代码:由工厂创建数据源(即连接池) BasicDataSourceFactory factory=new BasicDataSourceFactory(); //用类成员记住根据配置文件创建出来的连接池! ds=factory.createDataSource(pro); } catch (Exception e) { throw new ExceptionInInitializerError(e); } } //方法1:获取已装饰的连接 public static Connection getConnection() throws SQLException{ //DBCP在生成连接的时候已经装饰过Connection, //覆写了close方法,即归还到数据源(即连接池) return ds.getConnection(); } //方法2:释放连接 public static void release(Connection conn,Statement st,ResultSet rs){ if (conn!=null) { try { conn.close(); }catch (Exception e) { //只能记录!一旦抛出,后面的2条if代码就无法执行了 e.printStackTrace(); } conn=null; } if (st!=null) { try { st.close(); }catch (Exception e) { //只能记录!一旦抛出,后面的1条if代码就无法执行了 e.printStackTrace(); } st=null; } if (rs!=null) { try { rs.close(); }catch (Exception e) { e.printStackTrace(); } rs=null; } } }
JdbcUtils_Old位于utils包
package cn.itcast.utils; import java.io.InputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Properties; public class JdbcUtils_Old { private static Properties pro=new Properties(); /* * 静态成员Properties * 静态代码块:加载配置文件,注册驱动 * 静态方法1:获取连接 * 静态方法2:释放连接 * 工具类的异常只管抛,也可以转型后抛 * db.properties文件位于类目录下即src */ static{ String pro_name="db.properties"; InputStream in=JdbcUtils_Old.class.getClassLoader().getResourceAsStream(pro_name); try { pro.load(in); Class.forName(pro.getProperty("driver")); } catch (Exception e) { // 静态代码块的异常只能转型后抛出 throw new ExceptionInInitializerError(e); } } //方法1:获取连接 public static Connection getConnection() throws SQLException{ String url=pro.getProperty("url"); String user=pro.getProperty("user"); String password=pro.getProperty("password"); Connection conn=DriverManager.getConnection(url, user, password); return conn; } //方法2:释放连接 public static void release(Connection conn,Statement st,ResultSet rs){ if (conn!=null) { try { conn.close(); }catch (Exception e) { //只能记录!一旦抛出,后面的2条if代码就无法执行了 e.printStackTrace(); } conn=null; } if (st!=null) { try { st.close(); }catch (Exception e) { //只能记录!一旦抛出,后面的1条if代码就无法执行了 e.printStackTrace(); } st=null; } if (rs!=null) { try { rs.close(); }catch (Exception e) { e.printStackTrace(); } rs=null; } } }
package cn.itcast.utils; import java.io.InputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Properties; import javax.sql.DataSource; import org.apache.commons.dbcp.BasicDataSourceFactory; import cn.itcast.exception.DaoException; /**利用开源数据库连接池DBCP,创建自己的JDBC框架! DBCP内部增强Connection的close方法使用的是装饰模式! 1,导入两个jar包到工程下的lib目录,变成奶瓶 commons-dbcp-1.2.2.jar commons-pool.jar 2,设置src下的dbcpconfig.properties配置文件信息如库名! 3,定义静态成员DataSource记住DBCP创建出来的数据源(即连接池) 4,静态代码块中用BasicDataSourceFactory创建数据源(即连接池) 5,定义获取连接的方法 6,定义释放连接的方法 7,定义统一的update方法(增删改) 8,定义统一的查询方法(使用策略设计模式)*/ public class JdbcUtils { //定义成员记住DBCP创建出来的数据源(即连接池) private static DataSource ds; static{ try { String pro_name="dbcpconfig.properties"; InputStream in=JdbcUtils.class.getClassLoader().getResourceAsStream(pro_name); Properties pro = new Properties(); pro.load(in); //DBCP连接池--固定代码:由工厂创建数据源(即连接池) BasicDataSourceFactory factory=new BasicDataSourceFactory(); //用类成员记住根据配置文件创建出来的连接池! ds=factory.createDataSource(pro); } catch (Exception e) { throw new ExceptionInInitializerError(e); } } //方法1:从连接池中获取已装饰过的连接 public static Connection getConnection() throws SQLException{ //DBCP在生成连接的时候已经装饰过Connection, //覆写了close方法,即归还到数据源(即连接池) return ds.getConnection(); } //方法2:释放连接标准步骤! public static void release(Connection conn,Statement st,ResultSet rs){ if (conn!=null) { try { conn.close(); }catch (Exception e) { //只能记录!一旦抛出,后面的2条if代码就无法执行了 e.printStackTrace(); } conn=null; } if (st!=null) { try { st.close(); }catch (Exception e) { //只能记录!一旦抛出,后面的1条if代码就无法执行了 e.printStackTrace(); } st=null; } if (rs!=null) { try { rs.close(); }catch (Exception e) { e.printStackTrace(); } rs=null; } } //方法3:定义统一的update方法(增删改) public static void update(String sql,Object[] params){ Connection conn = null; PreparedStatement st = null; ResultSet rs = null; try{ conn = JdbcUtils.getConnection(); st = conn.prepareStatement(sql); //应该分情况讨论:参数数组为null或空,直接执行sql if(params==null || params.length==0){ st.executeUpdate(); return; } //否则用参数数组替换掉sql中的所有问号! for(int i=0;i<params.length;i++){ //第1个参数是1,第2个参数是2,依此类推 st.setObject(i+1,params[i]); } //替换完毕,执行完整的sql语句(增删改) st.executeUpdate(); }catch (Exception e) { throw new DaoException(e); }finally{ JdbcUtils.release(conn, st, rs); } } //方法4:定义统一的query方法(查询) public static Object query(String sql,Object[] params,ResultSetHandler rsh){ Connection conn = null; PreparedStatement st = null; ResultSet rs = null; try{ conn = JdbcUtils.getConnection(); st = conn.prepareStatement(sql); //应该分情况讨论:只有参数数组不为null或长度不为0,才进行参数替换! if(params!=null || params.length!=0){ //用参数数组替换掉sql中的所有问号! for(int i=0;i<params.length;i++){ //第1个参数是1,第2个参数是2,依此类推 st.setObject(i+1,params[i]); } } //替换完毕,执行完整的sql语句(查询) rs=st.executeQuery(); //我拿到结果不知道怎么处理,于是采用策略模式: //对外暴露一个ResultSetHandler接口,由调用该方法的人实现接口, //我再对其调用,将人家处理后的结果返回! return rsh.handle(rs); }catch (Exception e) { throw new DaoException(e); }finally{ JdbcUtils.release(conn, st, rs); } } }
c3p0-config.xml位于src类目录下
<?xml version="1.0" encoding="UTF-8"?> <c3p0-config> <default-config> <!--前面四个默认没有,自己对着文档加上的--> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost:3306/day16</property> <property name="user">root</property> <property name="password">root</property> <!--maxIdleTime单位是秒!--> <property name="maxIdleTime">30</property> <property name="acquireIncrement">5</property> <property name="initialPoolSize">10</property> <property name="minPoolSize">5</property> <property name="maxPoolSize">20</property> </default-config> <named-config name="flx"> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost:3306/day16</property> <property name="user">root</property> <property name="password">root</property> <property name="acquireIncrement">5</property> <property name="initialPoolSize">10</property> <property name="minPoolSize">5</property> <property name="maxPoolSize">20</property> </named-config> <named-config name="mysql"> <property name="acquireIncrement">50</property> <property name="initialPoolSize">100</property> <property name="minPoolSize">50</property> <property name="maxPoolSize">1000</property> <!-- intergalactoApp adopts a different approach to configuring statement caching --> <property name="maxStatements">0</property> <property name="maxStatementsPerConnection">5</property> </named-config> <named-config name="oracle"> <property name="acquireIncrement">50</property> <property name="initialPoolSize">100</property> <property name="minPoolSize">50</property> <property name="maxPoolSize">1000</property> <!-- intergalactoApp adopts a different approach to configuring statement caching --> <property name="maxStatements">0</property> <property name="maxStatementsPerConnection">5</property> </named-config> </c3p0-config>
dbcpconfig.properties位于src类目录下
#连接设置 driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/day16 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
用到的第3方jar包
mysql-connector-java-5.0.8-bin.jar
commons-dbcp-1.2.2.jar
commons-pool.jar
c3p0-0.9.2-pre1.jar
c3p0-oracle-thin-extras-0.9.2-pre1.jar
mchange-commons-0.2.jar