JDBC

一、JDBC基础

  1. JDBC全称:Java Database Connectivity(Java数据库连接)
  2. 通过JDBC,就可以实现同一种API访问不同的数据库,例如,我们的代码既可以与Oracle数据库连接,也可与MySql数据库连接,二者的区别只是使用了不同的驱动程序。
  3. JDBC的作用
    1) 建立与数据库的连接
    2) 执行SQL语句
    3) 获得sql语句的执行结果
  4. JDBC的4种常用驱动
    1) JDBC-ODBC桥:基本不用
    2) 直接将JDBC API映射成数据库特定的客户端API:性能高,但编码维护困难。
    3) 支持三层结构的JDBC访问方式,主要用于Applet阶段,通过Applet访问数据库
    4) 纯Java的,直接与数据库实例交互,该方式智能,它知道数据库使用的底层协议
    最常用的是第四种,而对性能有严格要求时,应选择第二种

二、JDBC的典型用法

  1. DriverManager:用于获取Connectoin对象
    public static synchronized Connection getConnection(String url,String user,String psw);
    可以看出,获取数据库连接是一个同步的方法。

  2. Connection:代表数据库连接对象,常用方法如下:
    1) Statement createStatement() throws Exception:获得Statement对象
    2) PreparedStatement preparedStatement(String sql):返回预编译的Statement对象
    3) CallableStatement prepareCall(String sql):返回调用存储过程的CallableStatement
    其中PreparedStatement和CallableStatement都是Statement的子类

  3. Connection的控制事务的方法
    1) Savepoint setSavepoint():创建一个事务保存点(中间点)
    2) void setTransactionIsolation(int level):设置事务隔离级别
    3) void rollback():回滚事务
    4) void rollback(Savepoint point):将事务回滚到指定的保存点
    5) void setAutoCommit(Boolean b):是否开启事务(false为开启)
    6) void commit():提交事务
    7) void setNetworkTimeout(Executor e,int milliseconds):设置数据库连接超时行为
  4. Statement:用于执行SQL语句的工具接口
    1) ResultSet executeQuery(String sql):执行查询SQL语句
    2) int executeUpdate():执行除了查询以外的其他SQL语句。执行DDL语句返回0,执行DML语句返回受影响行数
    3) boolean execute(String sql):执行任何SQL语句。如果执行SQL语句结果是ResultSet则返回true,否则返回false
    4) void closeOnCompletion():当所有依赖该Statement的ResultSet关闭时,则该Statement对象自动关闭
    通常没有必要使用execute()方法执行SQL语句,除非不清楚SQL语句类型,因为比较麻烦;一般使用比较简单的executeQuery()方法或executeUpdate()方法
  5. PreparedStatement:预编译的Statement对象
    1) 因为PreparedStatement对象已编译了SQL语句,所以它的有关执行SQL语句的方法不再需要传入SQL语句了,如executeQuery()、executeUpdate()、execute()
    2) setXxx(int index,Xxx value):给指定索引位置(占位符)传入值,如:
    setString(2,”张三”):给第二个占位符传入”张三”
    3) prearedStatement执行SQL语句的优点:
    a) 使用占位符,既避免了传参时拼接字符串,又避免了SQL注入
    b) 传参时若不知道参数类型时,可用setObject()方法
    c) 因为是预编译SQL语句(只需要传一条SQL语句就OK了),所以执行效率高
  6. ResultSet:结果集对象
    1) 通过列名或列索引获得数据
    getXxx(int index)、getXxx(String columnName)
    T getObject(int index)、getObject(String columnName)
    2) boolean absolute(int row):移动到第row行,row为负数时指倒数
    3) void beforeFirst():将记录指针移到第一行之前
    4) boolean first():将ResultSet的指针定位到首行
    5) boolean previous():定位到上一行
    6) boolean next():定位到下一行
    7) boolean last():定位到最后一行
    8) void afterLast():定位到最后一行之后
    9) void close():释放ResultSet对象
    注:ReslutSet的getString()方法可获得除Blob类型之外的任意类型类的值,因为这些类型都可以自动转换成字符串

三、JDBC编程示例与步骤

  1. 用executeQuery方法执行SQL语句:
public static void main(String[] args) throws Exception{
    Class.forName(“com.mysql.jdbc.Driver”); // 加载驱动
    String  url=”jdbc:mysql://127.0.0.1:3306/db”;
    Connection con= DriverManager.getConnection(url,”root”,”root”);//获得数据库连接
    Statement  st = con.createStatement();
    ResultSet  rs = st.executeQuery(“select * from user”);
    while(rs.next()){
        System.out.println(rs.getInt(“id”)+”==”+rs.getString(“username”));
    }
}
  1. 使用execute方法时部分代码示例
Statement  st = con.createStatement();
boolean  b = st.execute(“select * from user”);
if(b){ // 说明执行结果是ResultSet
     ResultSet  rs = st.getResult();
     int  columnNum = rs.getColumnCount(); // 获得列数
     while(){
        for(int i=0;i<columnNum;i++){
            System.out.println(rs.getString(i+1));
        }
    }
}else{
    //说明执行SQL结果不是查询,而是DDL或DML操作
}
  1. 用:PreparedStatement 执行SQL语句部分代码示例
 preparedStatement  ps = conn.preparedStatement(“insert into user values(“null,?”);
 for(int i=0;i<100;i++){
    ps.setString(1,”姓名”+i); // 给第一个占位符赋值
    ps.executeUpdate();
}
  1. 使用CallalbeStatement调用存储过程
CallalbeStatement cs = conn.prepareCall(“{call  add_user(?,?,?)}”); //add_user为存储过程名字
cs.setInt(1,4); //给第一个占位符传参
cs.setInt(2,5); //给第二个占位符传参
cs.registerOutParameter(3,Types.INTEGER);// 第三个占注册成传出参数,并指定类型
ex.execute();
System.out.println(“执行结果是:”+cs.getInt(3));
  1. 处理Blob类型数据,即Binary Long Object(二进制长对象)
    1) 插入数据库用PreparedStatement的setBinaryStream(int index , InputStream in)方法
    2) 取出Blob数据时,用ResultSet的getBlob(int index)方法获得Blob对象,Blob对象方法:
    getBinaryStream():取出输入流
    getBytes():取出二进制流
    3) Mysql数据库的Blob类型只能存64k的内容,mediumblob类型能存16M的内容
    6.ReslutSetMetaData
    Statement st = con.createStatement();
    ResultSet rs = st.executeQuery(sql); //sql字符串省略了
    ReslutSetMetaData rsmd = rs.getMetaData();
    int columnNum = rsmd.getColumnCount(); // 列数量
    String columnName = rsmd.getColumnName(2);// 获得索引为2的列的列名
    int columnType = rsmd.getColumnType(2); // 获得索引为2的列的列类型
    虽然ReslutSetMetaData对象可准确分析出ResultSet里包含多少列,以及每列的列名和类型,但使用它会有一定的系统开销,因此建议能不用就不用。

四、RowSet

  1. RowSet接口规范类图
    这里写图片描述
    离线RowSet:Connection关闭前,可将底层的数据读取到内存中进行离线操作
    连线RowSet:程序得到ResultSet后,必须立即处理数据,否则一旦Connection关闭,再通过ResultSet去读取时会报错

  2. 通过RowSetProvider创建RowSetFactory,然后通过RowSetFactory创建各类型的RowSet
     JdbcRowSet createJdbcRowSet()
     CachedRowSet createCachedRowSet()
     WebRowSet createWebRowSet()
     JoinRowSet createJoinRowSet()
     FilteredRowSet createFilteredRowSet()

  3. 离线RowSet(CachedRowSet)的分页
     setPageSize(int pageSize):设置返回条数
     previousPage():读取上一页记录
     nextPage():读取下一页记录
     populate(ResultSet rs, int startRow):填充RowSet startRow=(pageNo-1)*pageSize+1
    示例:
.省略部分代码
Statement  st = con.createStatement();
ResultSet  rs = st.executeQuery(sql);
RowSetFactory  f = RowSetProvider.newFactory();// 获得创建RowSet的工厂
CachedRowSet  cache = f.createCachedRowSet();// 创建离线RowSet
cache.setPageSize(10);  //每次取多少条
cache.populate(rs,(pageNo-1)*pageSize+1) );//缓存结果,并求出从第几条开始取
while(rs.next()){
    //…..
}

五、批量更新

  1. 批量更新,是将多个SQL语句一起提交给数据库执行(需要数据库支持)
  2. 注意事项
     批量更新时不能有select查询语句,否则程序会出错
     必须把批量操作当成单个事务,如果有一条SQL语句执行失败,则回滚到之前的状态
     MySql不支持Java8的executeLargeBatch() 和executeLargeUpdate()方法
  3. 示例
boolean  flag = con.getAutoCommit(); // 保存当前事务状态
    con.setAutoCommit(false); // 开启事务
    Statement  st = con.createStatement();
    st.addBatch(sql1);
    st.addBatch(sql2);
    st.addBatch(sql3);
    st.executeBatch(); // 执行批量操作
    con.commit(); // 提交事务
    con.setAutoCommit(flag); // 将事务恢复到之前的状态

六、使用连接池管理数据库连接

  1. 什么是连接池?
    连接池是生产并管理数据库连接的工厂
  2. 为什么需要连接池?
    数据库连接的建立和关闭都是极为耗资源的操作,频繁地打开和关闭连接,将造成系统性能低下。
  3. 连接池工作原理
    应用程序每次请求数据库连接时,都从连接池取出一个已有的空闲连接,使用完后,不会关闭连接,而是归还给连接池等待下一个请求来获取使用
  4. 两种连接池
     DBCP数据源:参见P638
     C3P0数据源:参见P639。C3P0要优于DBCP,Hibernate推荐使用C3P0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值