JDBC基础学习

JDBC笔记

一、连接数据库

方式一:
//创建驱动,获取Driver的实现类对象
Driver driver=new com.mysql.jdbc.Driver();
//jdbc:mysql:协议
//localhost:ip地址
//3306:端口号
//test:数据库
String url="jdbc:mysql://localhost:3306/test?characterEncoding=utf-8";

//将用户名和密码封装在info中
Properties info=new Properties();
info.setProperty("user","root");
info.setProperty("password","abc123");
Connection connect = driver.connect(url, info);
方式二:

方式一的迭代:使得在以下程序中看不到第三放jar包,使得程序具有更好的移植性

//1.创建驱动,获取Driver的实现类对象,使用反射
Class clazz = Class.forName("com.mysql.jdbc.Driver");
Driver driver = (Driver) clazz.newInstance();
//2.提供要连接的数据库
String url="jdbc:mysql://localhost:3306/test";
Properties info = new Properties();
info.setProperty("user","root");
info.setProperty("password","abc123");
Connection connect = driver.connect(url, info);
方式三:

使用DriverManager代替Driver

//1.创建驱动
Class clazz = Class.forName("com.mysql.jdbc.Driver");
Driver driver =(Driver) clazz.newInstance();
//注册驱动
DriverManager.deregisterDriver(driver);
String url="jdbc:mysql://localhost:3306/test";
String user="root";
String password="abc123";
//获取链接
Connection connection = DriverManager.getConnection(url, user, password);
方式四:

优化,因为在加载Driver类时,就会创建Driver对象

   //1.加载驱动
    Class.forName("com.mysql.jdbc.Driver");
    String url="jdbc:mysql://localhost:3306/test";
    String user="root";
    String password="abc123";
    //获取链接
    Connection connection = DriverManager.getConnection(url, user, password);
/**
 * 可省略以下步骤:
    Driver driver =(Driver) clazz.newInstance();
    //注册驱动
    DriverManager.deregisterDriver(driver);
 因为:在com.mysql.jdbc.Driver中执行了以下代码
 static {
     try {
        DriverManager.registerDriver(new Driver());
     } catch (SQLException var1) {
        throw new RuntimeException("Can't register driver!");
     }
 }
   */
方式五:final版

将信息放在文件中,通过流,将内容读取到代码中

//读取配置文件中的4个基本属性
InputStream is =  ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
Properties properties = new Properties();
properties.load(is);
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String url = properties.getProperty("url");
String driverClass = properties.getProperty("driverClass");
//获取驱动
Class.forName(driverClass);
Connection connection = DriverManager.getConnection(url, user, password);
System.out.println(connection);
说明:

因为通过JDBC连接数据库的方法是通用的,所以通常将其定义成静态方法封装在JDBCUtils类中,需要使用时,通过类名直接调用

同样的还有资源关闭

public class JDBCUtils {
    /**
     * 获取数据库的连接
     * @return
     * @throws Exception
     */
    public static Connection getConnection() throws Exception {
        //读取配置文件中的4个基本属性
        InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
        Properties properties = new Properties();
        properties.load(is);
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        String url = properties.getProperty("url");
        String driverClass = properties.getProperty("driverClass");
        //获取驱动
        Class.forName(driverClass);
        Connection connection = DriverManager.getConnection(url, user, password);
        return connection;
    }

    /**
     * 关闭资源
     * @param connection
     * @param statement
     */
    public  static void closeResource(Connection connection, Statement statement){

        if (statement!=null){
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (connection!=null){
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * 关闭资源
     * @param connection
     * @param statement
     */
    public  static void closeResource(Connection connection, Statement statement, ResultSet resultSet){

        if (statement!=null){
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (connection!=null){
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (resultSet!=null){
            try {
                resultSet.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

二、对数据库进行操作

1.使用statement

问题1:存在拼串操作,繁琐

问题2:存在SQL注入,危险

使用Statement的弊端:需要拼写SQL语句,并且存在SQL注入的问题,

// SELECT user,password FROM user_table WHERE USER = '1' or ' AND PASSWORD = '
// ='1' or '1' = '1';
String sql = "SELECT user,password FROM user_table WHERE USER = '" + userName + "' AND PASSWORD = '" + password
      + "'";

所以使用 PreparedStatement代替statement

Statement和PreparedStatement有什么区别?哪个性能更好?

答:与Statement相比,

①PreparedStatement接口代表预编译的语句,它主要的优势在于可以减少SQL的编译错误并增加SQL的安全性(减少SQL注射攻击的可能性);

②PreparedStatement中的SQL语句是可以带参数的,避免了用字符串连接拼接SQL语句的麻烦和不安全;

③当批量处理SQL或频繁执行相同的查询时,PreparedStatement有明显的性能上的优势,由于数据库可以将编译优化后的SQL语句缓存起来,下次执行相同结构的语句时就会很快(不用再次编译和生成执行计划)。

2.使用PreparedStatement对数据库进行增删改查操作

2.1对数据库进行增删改操作

因为增删改没有返回值,所以将其归为一类,将查询归为另一类

增删改操作区别为SQL语句不同,所以以修改为例

 Connection connection = null;
    PreparedStatement preparedStatement = null;
    try {
        //连接数据库
        connection = JDBCUtils.getConnection();
        //预编译SQL
        String sql="UPDATE customers SET NAME=? WHERE NAME=?";
        preparedStatement = connection.prepareStatement(sql);
        //填充占位符
        preparedStatement.setString(1,"胡歌");
        preparedStatement.setString(2,"霍建华");
        //操作
        preparedStatement.execute();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        //资源关闭
        JDBCUtils.closeResource(connection,preparedStatement);
    }

}

通用的增删改操作

/**
 * 通用的增删改操作
 */
public void currencyUpdate(String sql,Object...args){//传入SQL语句,以及填充的占位符的内容
    Connection connection = null;
    PreparedStatement preparedStatement = null;
    try {
        //获取连接
        connection = JDBCUtils.getConnection();
        //预编译SQL
        preparedStatement = connection.prepareStatement(sql);
        //填充占位符
        for (int i = 0; i <args.length ; i++) {
            preparedStatement.setObject(i+1,args[i]);
        }
        //执行操作
        preparedStatement.execute();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        //关闭资源
        JDBCUtils.closeResource(connection,preparedStatement);
    }
}
2.2对数据库进行查询操作

通用查询,返回一条记录,将查询的结果赋值给相对应的一个Java对象

一条记录是个对象,是一个结果集,所以需要用到resultSet,使用完之后需要资源关闭

/**
     * 通用查询,返回一条记录
     * @param sql
     * @param args
     * @return
     */
    public <T> T currencyQuery(Class<T> clazz,String sql,Object ...args){
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            connection = JDBCUtils.getConnection();
            preparedStatement = connection.prepareStatement(sql);
            //填充占位符
            for (int i = 0; i < args.length; i++) {
                preparedStatement.setObject(i+1,args[i]);
            }
            //获取结果集
            resultSet = preparedStatement.executeQuery();
            //获取元数据
            ResultSetMetaData metaData = resultSet.getMetaData();
            //获取列数
            int columnCount = metaData.getColumnCount();
            if (resultSet.next()){
                T t = clazz.newInstance();
                for (int i = 0; i < columnCount; i++) {
                    Object columValue = resultSet.getObject(i + 1);
                    //获取列名:getColumnName:不推荐属性
                    //获取别名:getColumnLabel
//                    String columnName = metaData.getColumnName(i + 1);
                    String columnLabel = metaData.getColumnLabel(i + 1);
                    //通过反射,获取对应的字段名
                    Field field = clazz.getDeclaredField(columnLabel);
                    //如果属性是私有的则无法操作,所以将其改为可操作的
                    field.setAccessible(true);
                    //将数据库中的值,赋值给对应类的对应属性
                    field.set(t,columValue);
                }
                return t;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //资源关闭
            JDBCUtils.closeResource(connection,preparedStatement,resultSet);
        }
        return null;
    }

通用查询,返回多条记录,将查询的结果赋值给相对应的多个Java对象

/**
 * 通用查询,返回多条记录
 * @param sql
 * @param args
 * @return
 */
public <T> List<T> getForList(Class<T> clazz, String sql, Object ...args){
    Connection connection = null;
    PreparedStatement preparedStatement = null;
    ResultSet resultSet = null;
    try {
        connection = JDBCUtils.getConnection();
        preparedStatement = connection.prepareStatement(sql);
        //填充占位符
        for (int i = 0; i < args.length; i++) {
            preparedStatement.setObject(i+1,args[i]);
        }
        //获取结果集
        resultSet = preparedStatement.executeQuery();
        //获取元数据
        ResultSetMetaData metaData = resultSet.getMetaData();
        //获取列数
        int columnCount = metaData.getColumnCount();
        ArrayList<T> list = new ArrayList<>();
        while (resultSet.next()){
            T t = clazz.newInstance();
            for (int i = 0; i < columnCount; i++) {
                Object columValue = resultSet.getObject(i + 1);
                //获取列名:getColumnName:不推荐属性
                //获取别名:getColumnLabel
                //String columnName = metaData.getColumnName(i + 1);
                String columnLabel = metaData.getColumnLabel(i + 1);
                //通过反射,获取对应的字段名
                Field field = clazz.getDeclaredField(columnLabel);
                //如果属性是私有的则无法操作,所以将其改为可操作的
                field.setAccessible(true);
                //将数据库中的值,赋值给对应类的对应属性
                field.set(t,columValue);
            }
            list.add(t);
        }
        return list;
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        //资源关闭
        JDBCUtils.closeResource(connection,preparedStatement,resultSet);
    }
    return null;
}
2.3 ORM编程思想
  • ORM编程思想:(object relational mapping,对象关系映射)
  • 一张数据表对应一个Java类
  • 一条记录对应一个Java对象

3.对Blob的操作

插入一张图片到数据库表的字段中

/**
 * 向数据表customers插入一条Blob字段
 */
@Test
public void testInsert(){
    Connection connection = null;
    PreparedStatement preparedStatement = null;
    try {
        connection = JDBCUtils.getConnection();
        String sql="insert into customers(name,email,birth,photo) values(?,?,?,?)";
        preparedStatement = connection.prepareStatement(sql);
        String name="晓晓";
        String email="xx@162.com";
        String birth="1998-01-02";
        //使用文件输入流,将文件读取到程序中
        FileInputStream photo = new FileInputStream(new File("1.jpg"));
        preparedStatement.setString(1, name);
        preparedStatement.setString(2, email);
        preparedStatement.setString(3, birth);
        //使用setBlob()将其填充到数据库中
        preparedStatement.setBlob(4, photo);
        int i = preparedStatement.executeUpdate();
        if (i>0){
            System.out.println("插入成功,影响"+i+"行");
        }else {
            System.out.println("插入失败");
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        JDBCUtils.closeResource(connection,preparedStatement);
    }
}

查询一条Blob数据,并将其存储在相应位置

/**
 * 查询Blob
 */
@Test
public void testQuery(){
    Connection connection=null;
    PreparedStatement preparedStatement=null;
    ResultSet resultSet=null;
    InputStream is= null;
    FileOutputStream fos= null;
    try {
        connection = JDBCUtils.getConnection();
        String sql="select id,name,email,birth,photo from customers where id=?";
        preparedStatement = connection.prepareStatement(sql);
        preparedStatement.setInt(1,22);
        resultSet = preparedStatement.executeQuery();
        if (resultSet.next()){
            int id = resultSet.getInt("id");
            String name = resultSet.getString("name");
            String email = resultSet.getString("email");
            Date birth = resultSet.getDate("birth");
            //获取Blob字段的信息
            Blob photo = resultSet.getBlob("photo");
            Customer customer = new Customer(id, name, email, birth);
            System.out.println(customer);
            //使用photo.getBinaryStream()将其转换成流
            is = photo.getBinaryStream();
            //新建一个输出文件流
            fos = new FileOutputStream("xiaoxiao.jpg");
            //操作
            byte[] buf = new byte[1024];
            int len=0;
            while ((len=is.read(buf))!=-1){
                fos.write(buf,0,len);
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        JDBCUtils.closeResource(connection,preparedStatement,resultSet);
        if (fos!=null){
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (is!=null){
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

4.使用PreparedStatement进行批量操作

4.1方式一:使用Statement

因为Statement操作批量数据太慢,且不能防止SQL注入,所以一般都是用PreparedStatement

4.2方式二:直接使用PreparedStatement

数据太多也会很慢,但是可以防SQL注入

/**
 * 方式二:使用preparedStatement代替statement
 */
@Test
public void test(){
    Connection connection = null;
    PreparedStatement preparedStatement = null;
    try {
        long start = System.currentTimeMillis();
        connection = JDBCUtils.getConnection();
        String sql="insert into goods(name) values (?)";
        preparedStatement = connection.prepareStatement(sql);
        for (int i = 0; i < 20000;i++) {
            preparedStatement.setString(1,"name_"+i);
            preparedStatement.execute();
        }
        long end = System.currentTimeMillis();
        System.out.println(end-start);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        JDBCUtils.closeResource(connection,preparedStatement);
    }
}
4.3方式三:使用preparedStatement.addBatch();

攒SQL,等SQL语句到达一定数量时,再进行操作

/**
 * 方式三:使用攒sql
 */
@Test
public void test1(){
    Connection connection = null;
    PreparedStatement preparedStatement = null;
    try {
        connection = JDBCUtils.getConnection();
        long strat = System.currentTimeMillis();
        String sql="insert into goods(name) values (?)";
        preparedStatement = connection.prepareStatement(sql);
        for (int i = 0; i < 20000; i++) {
            preparedStatement.setString(1,"name_"+i);
            //1.攒
            preparedStatement.addBatch();
            if (i%100==0){
             //达到条件执行
             preparedStatement.executeBatch();
             //清空
             preparedStatement.clearBatch();
            }
        }
        long end = System.currentTimeMillis();
        System.out.println(end-strat);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        JDBCUtils.closeResource(connection,preparedStatement);
    }
}
4.4方式四:设置不提交:connection.setAutoCommit(false);

每次执行SQL都会提交一次,影响效率

等所有语句都执行完成后,再一起提交,数据越多节省的时间也就越多

/**
 * 批量插入的方式四:设置不提交:connection.setAutoCommit(false);
 */
@Test
public void test2(){
    Connection connection = null;
    PreparedStatement preparedStatement = null;
    try {
        connection = JDBCUtils.getConnection();
        long strat = System.currentTimeMillis();
        //设置不提交,等所有操作完成之后,再进行提交
        connection.setAutoCommit(false);
        String sql="insert into goods(name) values (?)";
        preparedStatement = connection.prepareStatement(sql);
        for (int i = 1; i <=100000; i++) {
            preparedStatement.setString(1,"name_"+i);
            preparedStatement.addBatch();
            if (i%200==0){
                preparedStatement.executeBatch();
                preparedStatement.clearBatch();
            }
        }
        connection.setAutoCommit(true);
        long end = System.currentTimeMillis();
        System.out.println(end-strat);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        JDBCUtils.closeResource(connection,preparedStatement);
    }
}

三、事务

1.事务的ACID

事务的ACID是指什么?
原子性(Atomic):事务中各项操作,要么全做要么全不做,任何一项操作的失败都会导致整个事务的失败;
一致性(Consistent):事务结束后系统状态是一致的;
隔离性(Isolated):并发执行的事务彼此无法看到对方的中间状态;
持久性(Durable):事务完成后所做的改动都会被持久化,即使发生灾难性的失败。通过日志和同步备份可以在故障发生后重建数据。

2.数据库的隔离级别

1.对于同时运行的多个事务,当这些事务访问数据库中相同的数据时,如果没有采取必要的隔离机制,就会导致各种并发问题:

脏读: 对于两个事物T1, T2, T1读取了已经被T2更新但还没有被提交的字段。之后, 若T2回滚,T1读取的内容就是临时且无效的。

不可重复读: 对于两个事物 T1, T2, T1 读取了一个字段, 然后T2更新了该字段.之后, T1再次读取同一个字段,值就不同了。

幻读: 对于两个事物T1, T2, T1 从一个表中读取了一个字段,然后 T2在该表中插入了一些新的行。之后, 如果T1再次读取同一个表,就会多出几行.

2.数据库事务的隔离性: 数据库系统必须具有隔离并发运行各个事务的能力,使它们不会相互影响, 避免各种并发问题。

3.一个事务与其他事务隔离的程度称为隔离级别.数据库规定了多种事务隔离级别,不同隔离级别对应不同的干扰程度,隔离级别越高, 数据一致性就越好, 但并发性越弱。

4.数据库提供的4种事务隔离级别:READ UNCOMMITED(读已提交)、READ COMMITED(读已提交)、REPEATABLE READ(可重复读)、SERIALIZABLE(串行化)
Oracle 支持的2 种事务隔离级别:READ COMMITED(读已提交), SERIALIZABLE(串行化)。 Oracle默认的事务隔离级别为: READ COMMITED。

MySQL支持 4 中事务隔离级别,MySQL默认的事务隔离级别为: REPEATABLE READ(可重复读)。

5.在MySQL设置隔离级别

每启动一个 MySQL程序,就会获得一个单独的数据库连接。每个数据库连接都有一个全局变量 @@tx_isolation ,表示当前的事务隔离级别。 MySQL默认的隔离级别为 REPEATABLE READ(可重复读)

查看当前的隔离级别: SELECT@@tx_isolation;

设置当前 MySQL连接的隔离级别: set transaction isolation level read committed;

设置数据库系统的全局的隔离级别: set global transaction isolation levelread committed;

6.隔离级别测试

public void testTransactionIsolationRead() {
    	String sql = "SELECT balance FROM users WHERE id = 1";
    	Integer balance = getForValue(sql);
    	System.out.println(balance); 
    }
public <E> E getForValue(String sql, Object... args) {
    Connection connection = null;
    PreparedStatement preparedStatement = null;
    ResultSet resultSet = null;
    try {
        connection = JdbcUtils.getConnection();
        //获取默认的隔离级别:connection.getTransactionIsolation()==4(TRANSACTION_REPEATABLE_READ)
        //connection.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);//读未提交
        connection.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);//读已提交
        
        preparedStatement = connection.prepareStatement(sql);
        for (int i = 0; i < args.length; i++) {
            preparedStatement.setObject(i + 1, args[i]);
        }
        // 1. 得到结果集
        resultSet = preparedStatement.executeQuery();
        if (resultSet.next()) {
        	// 2. 取得结果
            return (E) resultSet.getObject(1);
        }
    } catch (Exception ex) {
        ex.printStackTrace();
    } finally {
    	JdbcUtils.closeResource(connection, null, preparedStatement, resultSet);
    }
    return null;
}

四、DAO(data access object 数据访问对象)

DAO的好处

1.隔离业务逻辑代码和数据访问代码

2.隔离不同数据库的实现的作用

DAO的组成

  1. TableDAO接口 把对数据库的所有操作定义为抽象方法

  2. TableDAOImpl实现类 不同数据库给出的DAO接口定义方法的具体实现

  3. 实体类 用于存放和传输对象数据

  4. 数据库工具类数据库连接和关闭工具

    避免了数据库连接和关闭代码的重复

定义一个TableDAO接口,此接口针对指定的数据库表,定义常用操作(增删改查)的抽象方法

定义一个TableDAOImpl实现类,继承BaseDAO抽象类,实现TableDAO接口

定义一个实体类,此类用于接收返回的数据

定义一个工具类JDBCUtils,用于封装获取数据库连接,关闭资源

五、数据库连接池

C3P0

Druid(常用):

//连接池创建一个就可以,所以定义为static 
private static InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("druid.properties");
public  static Connection getDruidConnection() throws Exception {
    //读取配置文件
    Properties properties = new Properties();
    properties.load(is);
    //连接数据库
    DataSource source = DruidDataSourceFactory.createDataSource(properties);
    //返回连接
    Connection connection = source.getConnection();
   return connection;
}

六、Apache-connect-dbutils

commons-dbutils 是Apache组织提供的开源的JDBC类库,封装了正对数据库的增删改查操作

dbutils测试

@Test//测试插入
public void testInsert(){
    Connection connection = null;
    try {
        QueryRunner queryRunner = new QueryRunner();
        connection = JDBCUtils.getDruidConnection();
        String sql="insert into customers(name,email,birth) values(?,?,?)";
        int i = queryRunner.update(connection, sql, "范闲", "fanxian@qq.com", "1888-01-02");
        System.out.println("插入了"+i+"条数据");
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        JDBCUtils.closeResource(connection,null);
    }
}
@Test//测试查询,情况一,返回一个对象
public void testQuery1() {
    Connection connection = null;
    try {
        QueryRunner runner = new QueryRunner();
        connection = JDBCUtils.getDruidConnection();
        String sql="select id,name,email,birth from customers where id=?";
        //根据query参数ResultSetHandler(结果集)来确定第三个参数
        //BeanHandler返回的是一个对象
        BeanHandler<Customer> handler = new BeanHandler<>(Customer.class);
        Customer customer = runner.query(connection, sql, handler, 21);
        System.out.println(customer);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        JDBCUtils.closeResource(connection,null);
    }
}
@Test//测试查询,情况二,返回多个对象的集合
public void testQuery2() {
    Connection connection = null;
    try {
        QueryRunner runner = new QueryRunner();
        connection = JDBCUtils.getDruidConnection();
        String sql = "select id,name,email,birth from customers where id<?";
        //根据query参数ResultSetHandler(结果集)来确定第三个参数
        //BeanListHandler返回的是多个对象的集合
        BeanListHandler<Customer> listHandler = new BeanListHandler<>(Customer.class);
        List<Customer> customers = runner.query(connection, sql, listHandler, 6);
        customers.forEach(System.out::println);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        JDBCUtils.closeResource(connection, null);
    }
}

@Test//测试查询,情况三,将字段及相应字段的值作为map中的key和value,返回一个map,
public void testQuery3() {
    Connection connection = null;
    try {
        QueryRunner runner = new QueryRunner();
        connection = JDBCUtils.getDruidConnection();
        String sql="select id,name,email,birth from customers where id=?";
        //根据query参数ResultSetHandler(结果集)来确定第三个参数
        //MapHandler返回的是一个对象
        MapHandler handler = new MapHandler();
        Map<String, Object> map = runner.query(connection, sql, handler, 21);
        System.out.println(map);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        JDBCUtils.closeResource(connection,null);
    }
}

@Test//测试查询,情况四,查询特殊值
public void testQuery4() {
    Connection connection = null;
    try {
        QueryRunner runner = new QueryRunner();
        connection = JDBCUtils.getDruidConnection();
        String sql="select count(*) from customers";
        //根据query参数ResultSetHandler(结果集)来确定第三个参数
        //ScalarHandler返回的是一个特殊值
        ScalarHandler handler = new ScalarHandler();
        Long i=(Long)runner.query(connection, sql, handler);
        System.out.println(i);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        JDBCUtils.closeResource(connection,null);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值