JDBC Unit02 JDBC核心API
来源:互联网 发布:用python写小游戏 编辑:程序博客网 时间:2024/05/20 16:00
一.连接池(数据源)
1.不用连接池时的问题
- 直接使用DriverManager时:
- 每次调用它都会创建新连接,而没有复用连接
- 它没有管理连接上限,当并发数大时可能导致数据库崩溃
2.连接池的作用
- 连接池的作用就是解决上述问题:
- 它能复用连接,提高效率
- 它能管理连接上限,避免数据库崩溃
3.有哪些常用连接池
- DBCP
- C3P0
4.连接池的工作原理
- 当创建连接池后,它会自动创建一批(配)连接放于池内
- 当用户调用它时,它会给用户一个连接,并将连接标为占用
- 当用户使用完连接后,将连接归还给连接池,它会将连接标为空闲
- 若连接池发现连接快不够用时,它会再创建一批(配)连接
- 若占用的连接达到数据库上限(配)时,连接池会让新用户等待
- 在高峰期过后,连接池会关闭一批(配)连接
5.如何使用连接池(*)
- sun规定了连接池的接口: DataSource
- DBCP实现了连接池的接口: BasicDataSource
二.Statement和PreparedStatement
1.它们的联系(背)
- 都是用来执行SQL的
- PreparedStatement extends Statement
2.它们的区别(背)
- Statement适合执行静态(无条件)SQL
- PreparedStatement适合执行动态(有条件)SQL
3.Statement原理(理解)
4.PreparedStatement原理(理解)
5.PS可以避免注入攻击
三.结果集
1.关于结果集的指针
2.元数据
- Meta: 根本、本质
- MetaData: 数据的根本,即数据的概述信息
- ResultSetMetaData: 对结果集的概述(描述)信息
案例代码
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<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); //rsorg.apache.commons.dbcp.DelegatingResultSet@27efef64 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); } }}
阅读全文
0 0
- JDBC Unit02 JDBC核心API
- JDBC核心API
- JDBC核心API
- JDBC核心API
- jdbc接口核心的API
- JDBC基础编程、核心API
- jdbc连接数据库和jdbc的核心api
- JDBC核心
- JDBC(一)--JDBC核心API/JDBC工具类/Statement/PreparedStatement/CallableStatement
- JDBC API
- JDBC API
- JDBC API
- JDBC API
- JDBC API
- JDBC接口核心的API、Statement接口详解
- java基础巩固---JDBC的接口核心API
- JDBC接口核心的API、Statement接口详解
- JDBC核心就几句
- 使用SharedPreferences实现简单的记住用户名和密码功能
- C#判断当前目录文件是否
- linux(ubuntu)配置tomcat+jdk
- SUM分析函数应用缺陷及解决办法
- hello world
- JDBC Unit02 JDBC核心API
- PopupWindow 封装详解
- 25 《培养高情商的孩子》 -豆瓣评分8.6
- 原生js放大镜demo
- 《大话西游》20年后重映(附影评:《大话西游》你真的看懂了吗?)
- Mac 上配置tomcat总结
- 卓越精英 | 曾经有人说他没有闪光点,一路摸索真自我,如今年薪8万多
- visibility和display的区别
- SEO