Unit02: JDBC核心API
db.properties
注意:如果使用连接池,可以在这个文件中增加对连接池的相关设置:
连接池参数,常用参数有:
- 初始连接数
- 最大连接数
- 最小连接数
- 每次增加的连接数
- 超时时间
- 最大空闲连接
- 最小空闲连接
# db connection parameters# key=valuedriver=oracle.jdbc.driver.OracleDriverurl=jdbc:oracle:thin:@192.168.201.227:1521:orcluser=openlabpwd=open123# datasource parametersinitSize=1maxSize=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