Unit02: JDBC核心API
db.properties
注意:如果使用连接池,可以在这个文件中增加对连接池的相关设置:
连接池参数,常用参数有:
- 初始连接数
- 最大连接数
- 最小连接数
- 每次增加的连接数
- 超时时间
- 最大空闲连接
- 最小空闲连接
# db connection parameters # key=value driver=oracle.jdbc.driver.OracleDriver url=jdbc:oracle:thin:@192.168.201.227:1521:orcl user=openlab pwd=open123 # datasource parameters initSize=1 maxSize=1
DBUtil.java
说明:DBUtil是DBTool的升级版,采用了连接池来管理连接。
package util; import java.io.IOException; import java.sql.Connection; import java.sql.SQLException; import java.util.Properties; import org.apache.commons.dbcp.BasicDataSource; /** * 1.DBUtil是DBTool的升级版 * 2.采用了连接池来管理连接 */ public class DBUtil { //DBCP连接池提供的实现类 private static BasicDataSource ds; static { Properties p = new Properties(); try { //1.读取参数 p.load(DBUtil.class.getClassLoader() .getResourceAsStream("db.properties")); String driver = p.getProperty("driver"); String url = p.getProperty("url"); String user = p.getProperty("user"); String pwd = p.getProperty("pwd"); String initSize = p.getProperty("initSize"); String maxSize = p.getProperty("maxSize"); //2.创建连接池(1次) ds = new BasicDataSource(); //3.向连接池设置参数 ds.setDriverClassName(driver); ds.setUrl(url); ds.setUsername(user); ds.setPassword(pwd); ds.setInitialSize(new Integer(initSize)); ds.setMaxActive(new Integer(maxSize)); } catch (IOException e) { //异常的处理原则: //1.记录日志(Log4j) e.printStackTrace(); //2.能解决就解决(看开发规范) //3.解决不了向上抛给调用者 //具体抛出哪种类型的异常看开发规范 throw new RuntimeException( "加载配置文件失败", e); } } public static Connection getConnection() throws SQLException { return ds.getConnection(); } /** * 1.目前我们使用连接都是连接池创建的 * 2.连接池重写了连接对象内部的close() * 3.目前close()内部的逻辑是归还: * - 清除连接对象内部包含的所有数据 * - 将连接对象状态设置为空闲态 */ public static void close(Connection conn) { if(conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException( "关闭连接失败", e); } } } }
Test.java
说明:这个类用于测试DBUtil
package jdbc; import java.sql.Connection; import java.sql.Date; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import org.junit.Test; import util.DBUtil; public class TestDay02 { /** * 1.测试DBUtil * 2.执行DQL * 查询部门ID为1的员工 */ @Test public void test1() { //假设页面传入的查询条件是 int deptno = 1; Connection conn = null; try { conn = DBUtil.getConnection(); System.out.println(conn); Statement smt = conn.createStatement(); String sql = "select * from emps_lhh " + "where deptno="+deptno; ResultSet rs = smt.executeQuery(sql); while(rs.next()) { System.out.println(rs.getInt("empno")); System.out.println(rs.getString("ename")); } } catch (SQLException e) { e.printStackTrace(); //测试代码可以适当简化异常处理 } finally { DBUtil.close(conn); } } /** * 演示如何使用PS执行DML */ @Test public void test2() { //假设页面传入的数据是 String ename = "曹操"; String job = "丞相"; int mgr = 0; Date hiredate = Date.valueOf("2017-01-22"); Double sal = 8000.0; Double comm = 9000.0; int deptno = 3; Connection conn = null; try { conn = DBUtil.getConnection(); //写sql时条件用?代替 String sql = "insert into emps_lhh values(" + "emps_seq_lhh.nextval," + "?,?,?,?,?,?,?)"; //创建PS并传入sql,PS会立刻发送此sql PreparedStatement ps = conn.prepareStatement(sql); //先设置条件:给?赋值 //ps.set类型(?的序号,?的值) ps.setString(1, ename); ps.setString(2, job); ps.setInt(3, mgr); ps.setDate(4, hiredate); ps.setDouble(5, sal); ps.setDouble(6, comm); ps.setInt(7, deptno); //发送参数,执行SQL(计划) ps.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } finally { DBUtil.close(conn); } } /** * 演示如何使用PS执行DQL */ @Test public void test3() { //假设页面传入的查询条件是 int empno = 1; Connection conn = null; try { conn = DBUtil.getConnection(); String sql = "select * from emps_lhh " + "where empno=?"; PreparedStatement ps = conn.prepareStatement(sql); ps.setInt(1, empno); ResultSet rs = ps.executeQuery(); if(rs.next()) { System.out.println(rs.getString("ename")); System.out.println(rs.getString("job")); } } catch (SQLException e) { e.printStackTrace(); } finally { DBUtil.close(conn); } } /** * 使用PS执行查询语句,可以避免注入攻击 */ @Test public void test4() { //假设页面传入的参数是 String user = "zhangsan"; String pwd = "a‘ or ‘b‘=‘b"; Connection conn = null; try { conn = DBUtil.getConnection(); String sql = "select * from users_lhh " + "where username=? " + "and password=?"; PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1, user); ps.setString(2, pwd); ResultSet rs = ps.executeQuery(); if(rs.next()) { System.out.println("登录成功"); } else { System.out.println("账号或密码错误"); } } catch (SQLException e) { e.printStackTrace(); } finally { DBUtil.close(conn); } } }
Test.java
- 演示如何从ResultSetMetaData中读取结果集相关的描述信息.
- 模拟转账业务.
- 批量添加员工(共108个,每批加50个)
- 添加部门及员工数据,添加员工时需要获取到部门的ID
package jdbc; import java.sql.Connection; import java.sql.Date; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import org.junit.Test; import util.DBUtil; public class TestDay03 { /** * 演示如何从ResultSetMetaData * 中读取结果集相关的描述信息. */ @Test public void test1() { //假设页面传入的查询条件是 int empno = 1; Connection conn = null; try { conn = DBUtil.getConnection(); String sql = "select * from emps_lhh " + "where empno=?"; PreparedStatement ps = conn.prepareStatement(sql); ps.setInt(1, empno); ResultSet rs = ps.executeQuery(); //获取结果集元数据,它是一个对象, //内部封装了对结果集的描述信息. ResultSetMetaData md = rs.getMetaData(); //多少列 System.out.println(md.getColumnCount()); //第1列的列名 System.out.println(md.getColumnName(1)); //第1列的类型的编号(常量) System.out.println(md.getColumnType(1)); //第1列的类型的名称 System.out.println(md.getColumnTypeName(1)); } catch (SQLException e) { e.printStackTrace(); } finally { DBUtil.close(conn); } } /** * 模拟转账业务. * * 假设此时用户已经登录了网银, * 并且已经输入了收款方账号和 * 转账的金额,点击了转账. * * 转账的步骤: * 1.验证收款方账号是否存在(查询) * 2.验证付款方余额是否够用(查询) * 3.将付款方余额-N元(修改) * 4.将收款方余额+N元(修改) */ @Test public void test2() { //假设用户输入的信息如下 //付款方账号 String payId = "00001"; //收款方账号 String recId = "00002"; //转账的金额 double mny = 1000.0; //转账是一个完整的业务流程,必须保证 //它的完整性,即该流程应处于一个事务 //之内,所以创建一个连接. Connection conn = null; try { conn = DBUtil.getConnection(); //取消自动提交事务 conn.setAutoCommit(false); //1.查询收款方账号并验证 String sql = "select * from accounts_lhh " + "where id=?"; PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1, recId); ResultSet rs = ps.executeQuery(); if(!rs.next()) { throw new SQLException("收款方账号不存在"); } double recMny = rs.getDouble("money"); //2.查询付款方余额并验证 String sql2 = "select * from accounts_lhh " + "where id=?"; PreparedStatement ps2 = conn.prepareStatement(sql2); ps2.setString(1, payId); ResultSet rs2 = ps2.executeQuery(); double payMny = 0.0; if(rs2.next()) { payMny = rs2.getDouble("money"); if(payMny<mny) { throw new SQLException("余额不足"); } } //3.修改付款方余额 String sql3 = "update accounts_lhh set " + "money=? where id=?"; PreparedStatement ps3 = conn.prepareStatement(sql3); ps3.setDouble(1, payMny-mny); ps3.setString(2, payId); ps3.executeUpdate(); Integer.valueOf("断电了"); //4.修改收款方余额 String sql4 = "update accounts_lhh set " + "money=? where id=?"; PreparedStatement ps4 = conn.prepareStatement(sql4); ps4.setDouble(1, recMny+mny); ps4.setString(2, recId); ps4.executeUpdate(); //转账是一个完整的过程,只需要在 //整个流程完成后,提交一次事务即可. conn.commit(); } catch (Exception e) { e.printStackTrace(); try { conn.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } } finally { DBUtil.close(conn); } } /** * 批量添加员工(共108个,每批加50个) */ @Test public void test3() { //这是一个完整的业务,只创建 //1个连接,提交1次事务 Connection conn = null; try { conn = DBUtil.getConnection(); conn.setAutoCommit(false); String sql = "insert into emps_lhh values(" + "emps_seq_lhh.nextval," + "?,?,?,?,?,?,?)"; PreparedStatement ps = conn.prepareStatement(sql); for(int i=1;i<=108;i++) { //每次循环都将数据暂存到ps上 ps.setString(1, "好汉"+i); ps.setString(2, "打劫"); ps.setInt(3, 0); ps.setDate(4, Date.valueOf("2017-01-23")); ps.setDouble(5, 6000.0); ps.setDouble(6, 4000.0); ps.setInt(7, 9); ps.addBatch(); //每循环50次发送一次数据 if(i%50==0) { ps.executeBatch(); //清空ps中的数据,以便于 //暂存下一轮的数据 ps.clearBatch(); } } //循环结束后,为了避免有零头(8), //再单独批量发送一次数据.由于这 //是最后一次发送,所以不用清空ps了 ps.executeBatch(); conn.commit(); } catch (SQLException e) { e.printStackTrace(); try { conn.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } } finally { DBUtil.close(conn); } } /** * 添加部门及员工数据 * 添加员工时需要获取到部门的ID */ @Test public void test4() { //假设页面传入的数据是 //部门 String dname = "财务部"; String loc = "杭州"; //员工 String ename = "郭嘉"; String job = "谋士"; int mgr = 0; Date hiredate = Date.valueOf("2017-01-23"); double sal = 6000.0; double comm = 2000.0; Connection conn = null; try { conn = DBUtil.getConnection(); conn.setAutoCommit(false); //增加部门 String sql = "insert into depts values(" + "depts_seq.nextval,?,?)"; //参数2是一个数组,声明需要ps记住 //的字段的名称,ps在执行SQL时会 //记住这些字段的值. PreparedStatement ps = conn.prepareStatement( sql, new String[]{"deptno"}); ps.setString(1, dname); ps.setString(2, loc); ps.executeUpdate(); //获取部门ID //返回的结果集中存储了一条数据, //该行数据包括我们让ps记录的所有字段. ResultSet rs = ps.getGeneratedKeys(); System.out.println("rs"+rs); //[email protected] rs.next(); //获取ps记录的字段时必须使用序号 int deptno = rs.getInt(1); System.out.println("deptno"+deptno); //deptno 4 //增加员工 String sql2 = "insert into emps values(" + "emps_seq.nextval," + "?,?,?,?,?,?,?)"; PreparedStatement ps2 = conn.prepareStatement(sql2); ps2.setString(1, ename); ps2.setString(2, job); ps2.setInt(3, mgr); ps2.setDate(4, hiredate); ps2.setDouble(5, sal); ps2.setDouble(6, comm); ps2.setInt(7, deptno); ps2.executeUpdate(); conn.commit(); } catch (SQLException e) { e.printStackTrace(); try { conn.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } } finally { DBUtil.close(conn); } } }
时间: 2024-10-08 13:22:51