JDBC学习笔记二

2019-09-02 09:50:20来源:博客园 阅读 ()

新老客户大回馈,云服务器低至5折

JDBC学习笔记二

JDBC学习笔记二

4.execute()方法执行SQL语句

execute几乎可以执行任何SQL语句,当execute执行过SQL语句之后会返回一个布尔类型的值,代表是否返回了ResultSet对象。

以下两个方法分别获得结果集或受影响的行数:

getResultSet(): 获取该Statement执行查询语句返回的ResultSet对象
getUpdateCount(): 获取该Statement执行DML语句所影响的记录行数

部分示例代码:

//stmt即为Connection对象创建的Statement
boolean hasResult = stmt.execute(sql);
if(hasResult){
    //获取结果集
    ResultSet rs = stmt.getResultSet;
}
else{
    //获取受影响的行数
    int count = stmt.getUpdateCount'
}

5.PreparedStatement

PerparedStatement时Statement的子接口,允许使用?占位符来代替具体值,在通过Connection对象创建PreparedStatement对象时需要传入SQL语句来进行预编译:

PreparedStatement pstmt = conn.prepareStatement("允许带占位符的sql语句");

PerparedStatement在执行SQL语句之前,要通过之前提到过的setXxx(int parameterIndex, Xxx value)方法来对占位符进行赋值。执行语句时的方法跟Statement方法相同,只是不需要传入SQL语句。

PreparedStatement还可以防止SQL注入,Statement如果要使用变量就需要拼接字符串,所以存在SQL注入的风险。

测试代码(使用之前的工具类以及Junit单元测试):

@Test
    public void pstmtTest() throws Exception{
        String sql = "select * from test where One > ?";
        Connection conn = JDBC2.getConnection();
        PreparedStatement pstmt = conn.prepareStatement(sql);
        //给占位符赋值
        pstmt.setInt(1, 1);
        //执行SQL语句
        ResultSet rs = pstmt.executeQuery();
        while(rs.next()){
            System.out.println(rs.getInt(1) + " "
                    + rs.getString(2) + " " + rs.getString(3));
        }
        //关闭连接
        JDBC2.close(conn, pstmt, rs);
    }

结果测试成功,这里就不再贴出

6.CallableStatement

调用存储过程使用CallableStatement,通过Connection的prepareCall方法来创建CallableStatement对象,创建该对象时需要传入调用存储过程的SQL语句,示例如下:

CallabeStatement cstmt = conn.prepareCall("call 存储过程名(?, ?, ?)");

可以通过CallableStatement的SetXxx(int indix, Xxx valie)方法为传入参数设置值,传出参数需要调用registerOutParameter方法来注册参数,示例如下:

cstmt.registerOutParameter(int index, Types.数据类型)

简单示例:

SQL中的存储过程

CREATE PROCEDURE simple_test(IN a int ,in b int, out sum int)
BEGIN
SET sum = a + b;
END;

JAVA代码

@Test
    public void cstmtTest()throws Exception{
        Connection conn = JDBC2.getConnection();
        //创建CallableStatement对象
        CallableStatement cstmt = conn.prepareCall("call simple_test(?, ?, ?)");
        //为传入参数设置值
        cstmt.setInt(1, 6);
        cstmt.setInt(2, 2);
        //注册参数
        cstmt.registerOutParameter(3,Types.INTEGER);
        cstmt.execute();
        System.out.println(cstmt.getInt(3));
    }

测试结果为8,这里就不再贴出

7.ResultSet

ResultSet为结果集,其中包含一个指针指向结果集中的某一行,可以利用内置的各种方法来移动指针,常用方法在之前的2.5中已经给出。

在JDK1.4之前的版本中,默认打开的ResultSet是不可滚动的,必须在创建Statement过PreStatement时需要传入额外参数,JDK1.5以后默认打开了ResultSet就是可滚动的,无需传入额外参数。

传入的参数有以下两种类型:

resultSetType:控制ResultSet的类型,该参数可以是三个值:
    ResultSet.TYPE_FORWARD_ONLY: 该常量控制记录指针只能向前移动
    ResultSet.TYPE_SCROLL_INSENSITIVE:可滚动结果集,但底层数据的改变不会影响ResultSet的值
    ResultSet.TYPE_SCROLL_SENSITIVE:可滚动结果集,底层数据的改变会影响ResultSet的值
resultSetConcurrency:控制ResultSet的并发类型,该参数可以是以下两个值:
    ResultSet.CONCUR_READ_ONLY:该常量指示ResultSet是只读的并发模式(默认)
    ResultSet.CONCUR_UPDATABLE:该常量指示ResultSet是可更新的并发模式

如果要创建可更新的结果集,查询语句查询的数据通常只能来自于同一个数据表,而且查询结果集中的数据列必须包含主键列,否则将会引起更新失败。

示例代码:

 @Test
    public void rsTest() throws Exception
    {
        Connection conn = JDBC2.getConnection();
        //创建可更新可滚动的ResultSet对象
        PreparedStatement pstmt = conn
                .prepareStatement("select * from test where One > ?",
                        ResultSet.TYPE_SCROLL_INSENSITIVE,
                        ResultSet.CONCUR_UPDATABLE);
        //给占位符赋值
        pstmt.setInt(1, 1);
        //执行SQL语句
        ResultSet rs = pstmt.executeQuery();
        //移动到最后
        rs.last();
        //获取指针当前所在的行数
        int rowCount = rs.getRow();
        System.out.println("修改前从后往前遍历:");
        for(int i = rowCount; i > 0; i--){
            //移动到第i行
            rs.absolute(i);
            System.out.println(rs.getInt(1) + " "
                    + rs.getString(2) + " " + rs.getString(3));
            //修改指针所在行的第二列的记录
            rs.updateString(2, "修改后的"+ i);
            //提交修改
            rs.updateRow();
        }
        //正序输出修改后的数据
        System.out.println("修改后从前往后遍历");
        for(int i = 1; i <= rowCount; i++){
            rs.absolute(i);
            System.out.println(rs.getInt(1) + " "
                    + rs.getString(2) + " " + rs.getString(3));
        }
        JDBC2.close(conn, pstmt, rs);
    }
}

数据库表中的数据也会随之更改。

8.ResultSetMetaData

MetaData的意思是元数据,即描述其他数据的数据,ResultSetMetaData封装了描述ResultSet对象的数据。

根据Result的getMetaDate()方法来获取ResultSetMetaData对象

常用方法如下:

int getColumnCount(): 返回该ResultSet的列数量
String getColumnName(int column): 返回指定索引的列名
int getColumnType(int column): 返回指定索引的列类型

使用过ResultSetMetaData对象后也要释放资源

9.事务

常用方法在中已经在2.2中写出

下面就贴一下简单的示例代码:

@Test
    public void transaction() throws Exception{
        Connection conn = JDBC2.getConnection();
        //关闭自动提交,开启事务
        conn.setAutoCommit(false);
        Statement stmt = conn.createStatement();
        //执行sql语句
        stmt.executeUpdate("insert into test values(4, '测试commit4', '测试commit4')");
        //设置回滚点
        //Savepoint savepoint1 = conn.setSavepoint("savepoint1");
        stmt.executeUpdate("insert into test values(5, '测试commit5', '测试commit5')");
        //回滚事务,不填写回滚点的话则撤销之前所有操作
        //conn.rollback(savepoint1);
        //提交事务(回滚之后也要提交)
        //conn.commit();
        JDBC2.close(conn, stmt, null);
    }

10.批量更新

多条SQL语句将会被作为一批操作被同时收集,并同时提交。

使用批量更新需要先创建一个Statement对象,然后使用该对象的addBatch方法将多条SQL语句同时收集起来,最后调用Statement对象的executeBatch同时执行这些sql语句,如下所示:

Statement stmt = conn.createStatement();
//收集多条SQL语句
stmt.addBatch(sql1);
stmt.addBatch(sql2);
stmt.addBatch(sql3);
...
//同时执行所有SQL语句
stmt.executeBatch();

执行executeBatch()方法将返回一个int[]数组,返回每次执行的所影响的行数,因此如果addBatch()时添加查询语句运行时会出现错误。因此可以在执行批处理前开启事务,当出现错误时回滚到初始状态。

11.连接池

数据库的连接及关闭非常耗费系统资源,为了减少资源浪费,提高程序运行效率,可以采用数据库连接池。

数据库连接池:当程序启动时,系统自动建立足够的数据库连接,并将这些连接组成一个连接池。每次应用程序请求数据库连接时,无须重新打开连接,而是从池中取出已有的连接使用,当使用完后,不再关闭数据库连接,而是将连接归还给连接池。连接池就类似于之前所学的对象工厂(也是在程序开始运行时,将properties文件中的类实例化)

C3P0和DBCP对比:

DBCP C3P0
对数据连接处理的方式 提供最大连接数 提供最大空闲时间
什么时候挂断 当连接超过最大连接数 自动回收连接
连接资源是否释放 需要自己手动释放资源 需要自己手动释放资源
效率 效率比较高 效率没有DBCP高
推荐使用 spring开发 hibernate开发

11.1.DBCP

需要jar包:common-dbcpcommon-poolcommon-collections

maven依赖:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-dbcp2</artifactId>
    <version>2.1.1</version>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.6.1</version>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.1</version>
</dependency>

简单模板:

import org.apache.commons.dbcp2.BasicDataSource;
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

public class DBCP {
    private static BasicDataSource ds;
    static{
        try{
            ds = new BasicDataSource();
            //读取配置文件
            Properties prop = new Properties();
            prop.load(new FileInputStream("src/main/resources/datasource.properties"));
            //设置驱动,高版本jar包不需要这一步,如果写的话写成“com.mysql.jdbc.Driver”
            //ds.setDriverClassName(prop.getProperty("driver"));
            //设置url
            ds.setUrl(prop.getProperty("url"));
            //用户名
            ds.setUsername(prop.getProperty("username"));
            //密码
            ds.setPassword(prop.getProperty("password"));
            //设置连接池初始连接数
            ds.setInitialSize(Integer.parseInt(prop.getProperty("initialsize")));
            //设置最大活动连接数
            ds.setMaxTotal(Integer.parseInt(prop.getProperty("maxactive")));
            //设置最小空闲连接
            ds.setMinIdle(Integer.parseInt(prop.getProperty("minidle")));
        }catch (IOException e){
            e.printStackTrace();
        }
        System.out.println("finish init");
    }

    public static Connection getConnetion(){
        try {
            return ds.getConnection();
        }catch (SQLException e){
            e.printStackTrace();
            return null;
        }
    }
}

上面的属性配置只是常用配置,完整的配置请参考官方文档。

测试代码:

@Test
    public void DBCPTest() {
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        try{
            conn = DBCP.getConnetion();
            stmt = conn.createStatement();
            rs = stmt.executeQuery("select * from test");
            while(rs.next())
                System.out.println(rs.getInt(1) + " "
                        + rs.getString(2) + " " + rs.getString(3));
        }catch (SQLException e){
            e.printStackTrace();
        }
        finally {
            //关闭连接
            try {
                if(rs != null)
                    rs.close();
                if(stmt != null)
                    stmt.close();
                if(conn != null)
                    conn.close();
            }catch (SQLException e){
                e.printStackTrace();
            }
        }
    }

11.2.C3P0

需要jar包:c3p0;

maven依赖:

<dependency>
    <groupId>com.mchange</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.5.2</version>
</dependency>

简单模板:

将DBCP中的BasicDataSource替换为ComboPooledDataSource

驱动,url,用户名和密码设置方式相同,剩余的请参考官方文档


原文链接:https://www.cnblogs.com/ys1109/p/11446974.html
如有疑问请与原作者联系

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:JavaWeb 分层设计、MVC

下一篇:Java多线程编程(2)--多线程编程的术语与概念