JDBC核心技术2

本文介绍了JDBC中的批量插入,强调了PreparedStatement相对于Statement的优势,包括性能优化和防止SQL注入。接着详细讨论了数据库事务,解释了ACID属性,分析了并发问题如脏读、不可重复读和幻读。还概述了四种事务隔离级别。此外,文章提到了DAO模式和数据库连接池的重要性,特别是C3P0、DBCP和Druid这三种开源连接池的特性。最后,简述了Apache-DBUtils如何简化CRUD操作。
摘要由CSDN通过智能技术生成

5. 批量插入

/*使用PreparedStatement实现批量数据的操作*
* CREATE TABLE goods(
id INT PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(25)
);
* 向goods表中插入1w条数据
 */
public class InsertTest {
    //批量添加方式1
    @Test
    public void test1() throws Exception {
        Connection connection = JDBCUtils.getConnection();
        String sql = "insert into goods(name) values(?)";
        PreparedStatement ps = connection.prepareStatement(sql);
        for (int i = 1; i <= 10000; i++) {
            ps.setObject(1, "name_" + i);
            //“攒”sql
            ps.addBatch();
            if (i % 500 == 0) {
                //执行batch
                ps.executeBatch();
                //清空batch
                ps.clearBatch();
            }

        }
        JDBCUtils.closetResource(connection, ps);
    }

    //批量插入方式2,优化1
    @Test
    public void test2() throws Exception {
        Connection connection = JDBCUtils.getConnection();
        connection.setAutoCommit(false);
        String sql = "insert into goods(name) values(?)";
        PreparedStatement ps = connection.prepareStatement(sql);
        for (int i = 1; i <= 10000; i++) {
            ps.setObject(1, "name_" + i);
            //“攒”sql
            ps.addBatch();
            if (i % 500 == 0) {
                //执行batch
                ps.executeBatch();
                //清空batch
                ps.clearBatch();
            }
        }
        connection.commit();
        JDBCUtils.closetResource(connection, ps);
    }
}

PreparedStatement VS Statement
PreparedStatement是Statement的子接口,表示一条预编译过的SQL语句
PreparedStatement最大可能提升性能,对预编译语句提供性能优化,语句在被DBServer的编译器编译后的执行代码被缓存下来,那么下次调用时只要相同的预编译语句就不需要编译,只要将参数直接传入编译过的语句执行代码中就会被执行
PreparedStatement可以防止SQL注入问题,还可以对Blob字段进行操作

6. 数据库事务

6.1 JDBC事务处理

  • 事务:一组逻辑操作单元,使数据从一种状态变换到另一种状态
  • 事务处理原则:保证所有事务都作为一个工作单元来执行,当在一个事务中执行多个操作时,要么u松油的事务都被提交(commit),要么放弃所有修改,整个事务回滚(rollback)到最初状态
public class TransactionTest {
    /*
     * AA用户给BB转账100
     * */
    @Test
    public void test1()  {
        Connection conn = null;
        try {
            conn = JDBCUtils.getConnection();
            //取消数据的自动取消
            conn.setAutoCommit(false);
//            System.out.println(conn.getAutoCommit());
            String sql1 = "update user_table set balance = balance -100 where user=?";
            update2(conn, sql1, "AA");
            //模拟异常
            System.out.println(10 / 0);

            String sql2 = "update user_table set balance = balance +100 where user=?";
            update2(conn, sql2, "BB");
            System.out.println("转账成功");
            //提交数据
            conn.commit();
        } catch (Exception e) {
            e.printStackTrace();
            //回滚数据
            try {
                conn.rollback();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        } finally {
            JDBCUtils.closetResource(conn, null);
        }
    }

    //通用的增删改操作--version1.0
    public int update(String sql, Object... args) {//sql中占位符的个数与可变形参的长度相同
        Connection conn = null;
        PreparedStatement ps = null;
        try {
            //1.获取数据库的连接
            conn = JDBCUtils.getConnection();
            //2.预编译sql语句,返回PreparedStatement的实例
            ps = conn.prepareStatement(sql);
            //3.填充占位符
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1, args[i]);//!!!!
            }
            //4.执行
            ps.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //5.关闭资源
            JDBCUtils.closetResource(conn, ps);
        }
        return 0;
    }

    //考虑事务后的操作--version2.0
    public int update2(Connection conn, String sql, Object... args) {
        PreparedStatement ps = null;
        try {
            //2.预编译sql语句,返回PreparedStatement的实例
            ps = conn.prepareStatement(sql);
            //3.填充占位符
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1, args[i]);//!!!!
            }
            //4.执行
            ps.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //主要针对于数据库连接池时修改其为自动提交数据
            try {
                conn.setAutoCommit(true);
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            //5.关闭资源
            JDBCUtils.closetResource(null, ps);
        }
        return 0;
    }
}

6.2 事务的ACID属性

  1. 原子性(Atomicity)是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生
  2. 一致性(Consistency)必须使数据库从一个一致性状态变换到另外一个一致性状态
  3. 隔离性(Isolation)是指一个事务的执行不被其他事务干扰,一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰
  4. 持久性(Durability)指一个事务一旦被提交,对数据库中数据的改变是永久的,接下来的其他操作不应该对其有任何影响

6.2.1 数据库并发问题

  • 脏读:对于两个事务T1,T2,T1读取了已经被T2更新但还没有被提交的字段。之后,若T2回滚,T1读取的内容就是临时且无效的
  • 不可重复读:T1读取了一个字段,然后T2更新了该字段。之后,T1再次读取同一个字段,值就不同了
  • 幻读:T1从一个表中读取了一个字段,然后T2在该表中插入了新的行。之后,如果T1再次读取同一个表,就会多出几行

6.2.2 四种隔离级别

隔离级别描述
READ UNCOMMITTED(读未提交数据)允许事务读取未被其他事务提交的变更,脏读、不可重复读、幻读都会出现
READ COMMITED(读已提交数据)只允许事务读取已经被其他事务提交的变更,可以避免脏读,但不可重复读和幻读仍然出现
REPEATABLE READ(可重复读)确保事务可以多次从一个字段中读取相同的值,在这个事务持续期间,禁止其他事务对这个字段进行更新,可以避免脏读和不可重复读,幻读依旧存在
SERIALIZABLE(串行化)确保事务可以从一个表读取相同的行。禁止其他事务对该表执行增删改操作,所有问题都可避免,但性能低下
  • Oracle默认READ COMMITD,Mysql默认REPEATABLE READ
    //事务
    @Test
    public void test2() throws Exception {
        Connection conn = JDBCUtils.getConnection();
        //获取当前连接的隔离级别
        System.out.println(conn.getTransactionIsolation());
        //取消自动提交
        conn.setAutoCommit(false);
        String sql = "select user,password,balance from user_table where user=?";
        List<User> users = getInstance(conn, User.class, sql, "CC");
        users.forEach(System.out::println);
    }

    @Test
    public void test3() throws Exception {
        Connection conn = JDBCUtils.getConnection();
        //取消自动提交
        conn.setAutoCommit(false);
        String sql = "update user_table set balance =? where user=?";
        update2(conn, sql, 8888, "CC");

        Thread.sleep(15000);
        System.out.println("修改结束");
    }

    //通用的查询操作,用于返回数据表中的记录--考虑事务version2.0
    public <T> List<T> getInstance(Connection conn, Class<T> clazz, String sql, Object... args) {
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            ps = conn.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1, args[i]);
            }
            rs = ps.executeQuery();
            //获取结果集的元数据
            ResultSetMetaData rsmd = rs.getMetaData();

            int columnCount = rsmd.getColumnCount();
            //创建集合对象
            ArrayList<T> list = new ArrayList<>();
            while (rs.next()) {
                T t = clazz.newInstance();
                //处理一行结果集中的每个列
                for (int i = 0; i < columnCount; i++) {
                    //获取列值
                    Object columnValue = rs.getObject(i + 1);
                    //获取每个列的列名
                    String columnName = rsmd.getColumnName(i + 1);
                    //给cust对象指定的columnName属性,赋值为columnValue,通过反射
                    Field field = clazz.getDeclaredField(columnName);
                    field.setAccessible(true);
                    field.set(t, columnValue);
                }
                list.add(t);
            }
            return list;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closetResource(null, ps, rs);
        }
        return null;
    }

7. DAO及其实现类

7.1 BaseDAO

//封装了针对于数据表的通用的操作
//DAO(databse access object)
public abstract class BaseDAO {
    //考虑事务后的操作--version2.0
    public int update2(Connection conn, String sql, Object... args) {
        PreparedStatement ps = null;
        try {
            //2.预编译sql语句,返回PreparedStatement的实例
            ps = conn.prepareStatement(sql);
            //3.填充占位符
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1, args[i]);//!!!!
            }
            //4.执行
            ps.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //主要针对于数据库连接池时修改其为自动提交数据
            try {
                conn.setAutoCommit(true);
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            //5.关闭资源
            JDBCUtils.closetResource(null, ps);
        }
        return 0;
    }

    //通用的查询操作,用于返回数据表中的记录--考虑事务version2.0
    public <T> List<T> getInstance(Connection conn, Class<T> clazz, String sql, Object... args) {
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            ps = conn.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1, args[i]);
            }
            rs = ps.executeQuery();
            //获取结果集的元数据
            ResultSetMetaData rsmd = rs.getMetaData();

            int columnCount = rsmd.getColumnCount();
            //创建集合对象
            ArrayList<T> list = new ArrayList<>();
            while (rs.next()) {
                T t = clazz.newInstance();
                //处理一行结果集中的每个列
                for (int i = 0; i < columnCount; i++) {
                    //获取列值
                    Object columnValue = rs.getObject(i + 1);
                    //获取每个列的列名
                    String columnName = rsmd.getColumnName(i + 1);
                    //给cust对象指定的columnName属性,赋值为columnValue,通过反射
                    Field field = clazz.getDeclaredField(columnName);
                    field.setAccessible(true);
                    field.set(t, columnValue);
                }
                list.add(t);
            }
            return list;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closetResource(null, ps, rs);
        }
        return null;
    }

    //用于查询特殊值的通用方法
    public <E> E getValue(Connection con, String sql, Object... args) throws SQLException {
        PreparedStatement ps = con.prepareStatement(sql);
        for (int i = 0; i < args.length; i++) {
            ps.setObject(i + 1, args[i]);
        }
        ResultSet rs = ps.executeQuery();
        if (rs.next()) {
            return (E) rs.getObject(1);
        }
        JDBCUtils.closetResource(null, ps, rs);
        return null;
    }
}

7.2 CustomerDAO

//此接口用于规范针对于customers表的常用操作
public interface CustomerDAO {
    //将cust对象添加到数据库中
    void insert(Connection connection, Customer cust);

    //根据指定的id,删除表中的一条记录
    void deleteById(Connection connection, int id);

    //针对内存中的cust对象修改数据表中的记录
    void updateById(Connection connection, Customer customer);

    //指定id查询得到对应的Customer对象
    Customer getCustomerById(Connection connection, int id);

    //查询表中所有记录构成的集合
    List<Customer> getAll(Connection connection);

    //返回数据表中的数据的条目数
    Long getCount(Connection connection);

    //返回数据表中最大的生日
    Date getMaxBirth(Connection connection);
}

7.3 CustomerDAOImpl

public class CustomerDAOImpl extends BaseDAO implements CustomerDAO {
    @Override
    public void insert(Connection connection, Customer cust) {
        String sql = "insert into customers(name,email,birth)values(?,?,?)";
        update2(connection, sql, cust.getName(), cust.getEmail(), cust.getBirth());
    }

    @Override
    public void deleteById(Connection connection, int id) {
        String sql = "delete from customers where id=?";
        update2(connection, sql, id);
    }

    @Override
    public void updateById(Connection connection, Customer customer) {
        String sql = "update customers set name=?,email=?,birth =? where id = ?";
        update2(connection, sql, customer.getName(), customer.getEmail(), customer.getBirth(), customer.getId());
    }

    @Override
    public Customer getCustomerById(Connection connection, int id) {
        return null;
    }

    @Override
    public List<Customer> getAll(Connection connection) {
        String sql = "select id,name,email,birth from customers";
        List<Customer> list = getInstance(connection, Customer.class, sql);
        return list;
    }

    @Override
    public Long getCount(Connection connection) {
        String sql = "select count(*) from customers";
        return getValue(connection, sql);
    }

    @Override
    public Date getMaxBirth(Connection connection) {
        String sql="select max(birth) from customers";
        return getValue(connection,sql);
    }
}

7.4 CustomerDAOImpl

public class CustomerDAOImplTest {
    CustomerDAOImpl dao = new CustomerDAOImpl();

    @Test
    public void testInsert() {
        Connection connection = null;
        try {
            connection = JDBCUtils.getConnection();
            Customer customer = new Customer(1, "zhangsan", "zhangs@zs.com", new Date(46474874465L));
            dao.insert(connection, customer);
            System.out.println("添加成功");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closetResource(connection, null);
        }
    }

    @Test
    public void testDeleteById() {
        Connection connection = null;
        try {
            connection = JDBCUtils.getConnection();
            dao.deleteById(connection, 23);
            System.out.println("删除成功");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closetResource(connection, null);
        }
    }

    @Test
    public void testUpdateCustomer() {
        Connection connection = null;
        try {
            connection = JDBCUtils.getConnection();
            Customer customer = new Customer(22, "zhangsan", "zhangs@zs.com", new Date(46474874465L));
            dao.updateById(connection, customer);
            System.out.println("修改成功");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closetResource(connection, null);
        }
    }

    @Test
    public void testGetAll() {
        Connection connection = null;
        try {
            connection = JDBCUtils.getConnection();
            List<Customer> list = dao.getAll(connection);
            list.forEach(System.out::println);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closetResource(connection, null);
        }
    }

    @Test
    public void testGetCount() {
        Connection connection = null;
        try {
            connection = JDBCUtils.getConnection();
            System.out.println(dao.getCount(connection));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closetResource(connection, null);
        }
    }

    @Test
    public void testMaxBirth() {
        Connection connection = null;
        try {
            connection = JDBCUtils.getConnection();
            System.out.println(dao.getMaxBirth(connection));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closetResource(connection, null);
        }
    }
}

8. 数据库连接池

8.1数据库连接池技术

  • 为数据库连接建立了一个“缓冲池”,预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,从“缓冲池”中取出一个,使用完毕后再放回去
  • 数据库连接池负责分配、管理和释放数据库连接,他允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个

8.2 多种开源数据库连接池

  • JDBC的数据库连接池使用javax.sql.DataSource来表示,DataSource只是一个接口,该接口通常由服务器(Weblogic,WebSphere,Tomcat)提供实现
  • DBCP是Apache提供的数据库连接池,tomcat服务器自带dbcp数据库连接池,速度较C3P0快,但存在BUG,Hibernate3已不再支持
  • C3P0速度较慢,稳定还可以,hibernate官方推荐使用
  • Druid是阿里提供的,记说是集优点于一身的
  • DatSource通常被称为数据源,他包含连接池和连接池管理两个部分,习惯上把DataSource称为连接池

8.2.1 C3P0

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
    <!-- This app is massive! -->
    <named-config name="helloc3p0">
        <!--提供获取连接的4个基本信息 -->
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/test</property>
        <property name="user">root</property>
        <property name="password">123456</property>

        <!-- 进行数据库连接池管理的基本信息-->
        <!--当数据库连接池中的连接数不够时,C3P0一次性向数据库服务器申请的连接数-->
        <property name="acquireIncrement">5</property>
        <!--C3P0数据库连接池中初始化时的连接数-->
        <property name="initialPoolSize">10</property>
        <!--维护的最少连接数-->
        <property name="minPoolSize">10</property>
        <!--维护的最多的连接数-->
        <property name="maxPoolSize">100</property>
        <!--维护最多的Statement个数-->
        <property name="maxStatements">50</property>
        <!--每个连接可以最多使用Statement的个数-->
        <property name="maxStatementsPerConnection">2</property>
    </named-config>
</c3p0-config>
public class C3P0Test {

    //方式一
    @Test
    public void testGetConnection() throws Exception {
        //获取C3P0数据库连接池
        ComboPooledDataSource cpds = new ComboPooledDataSource();
        cpds.setDriverClass("com.mysql.jdbc.Driver"); //loads the jdbc driver
        cpds.setJdbcUrl("jdbc:mysql://localhost/test");
        cpds.setUser("root");
        cpds.setPassword("123456");

        //通过设置相关的参数,对数据库连接池进行管理
        //设置初始时数据库连接池中的连接数
        cpds.setInitialPoolSize(10);

        Connection connection = cpds.getConnection();
        System.out.println(connection);
        //销毁C3P0数据库连接池,一般不需要
        DataSources.destroy(cpds);
    }

    //方式二,使用配置文件
    @Test
    public void testConnection() throws SQLException {
        ComboPooledDataSource cpds = new ComboPooledDataSource("helloc3p0");
        Connection connection = cpds.getConnection();
        System.out.println(connection);
    }
}

8.2.2 DBCP

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost/test
username=root
password=123456

initialSize=10
public class DBCPTest {
    //测试DBCP的数据库连接池技术
    //方式一
    @Test
    public void testGetConnection() throws SQLException {
        //创建DBCP的数据库连接池
        BasicDataSource source = new BasicDataSource();
        //设置基本信息
        source.setDriverClassName("com.mysql.jdbc.Driver");
        source.setUrl("jdbc:mysql://localhost/test");
        source.setUsername("root");
        source.setPassword("gaiwei200888");

        source.setInitialSize(10);
        source.setMaxActive(10);
        Connection connection = source.getConnection();
        System.out.println(connection);
    }

    //方式二。使用配置文件
    @Test
    public void test2() throws Exception {
        Properties pros = new Properties();
        InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("dbcp.properties");
        pros.load(is);
        DataSource dataSource = BasicDataSourceFactory.createDataSource(pros);
        Connection connection = dataSource.getConnection();
        System.out.println(connection);
    }
}

8.2.3 Druid(德鲁伊)

url=jdbc:mysql:///test
username=root
password=123456
driverClassName=com.mysql.jdbc.Driver
initialSize=8
public class DruidTest {
    @Test
    public void getConnection() throws Exception {
        Properties pros = new Properties();
        InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("druid.properties");
        pros.load(is);
        DataSource source = DruidDataSourceFactory.createDataSource(pros);
        Connection connection = source.getConnection();
        System.out.println(connection);
    }
}
public class JDBCUtil {
    //数据库连接池只i需要提供一个即可
    private static ComboPooledDataSource cpds = new ComboPooledDataSource("helloc3p0");
    private static DataSource source;

    static {
        Properties pros = new Properties();
        InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("dbcp.properties");
        try {
            pros.load(is);
            source = BasicDataSourceFactory.createDataSource(pros);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //使用C3P0数据库连接池技术
    public static Connection getConnection1() throws SQLException {
        Connection connection = cpds.getConnection();
        return connection;
    }

    public static Connection getConnection2() throws Exception {
        //创建一个DBCP数据库连接池
        Connection connection = source.getConnection();
        return connection;
    }

    private static DataSource dataSource;

    static {
        Properties pros = new Properties();
        InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("druid.properties");
        try {
            pros.load(is);
            dataSource = DruidDataSourceFactory.createDataSource(pros);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static Connection getConnection3() throws SQLException {

        Connection connection = dataSource.getConnection();
        return connection;
    }
}

9. Apache-DBUtils实现CRUD操作

  • commons-dbutils是Apache提供的一个开源JDBC工具类库,是对JDBC的简单封装,使用dbutils极大简化jdbc编码的工作量
  • API介绍org.apache.commons.dbutils.QueryRunner
  • org.apache.commons.dbutils.ResultSertHandler
  • 工具类org.apache.commons.dbutils.DbUtils

9.1 主要API的使用

public class QueryRunnerTest {
    //插入
    @Test
    public void testInert() throws SQLException {
        QueryRunner runner = new QueryRunner();
        Connection connection = JDBCUtil.getConnection3();
        String sql = "insert into customers (name,email,birth) values(?,?,?)";
        int inertCount = runner.update(connection, sql, "lilili", "lili@li.com", "1997-02-06");
        System.out.println(inertCount);
    }

    //查询,BeanHandler是ResultSetHandler接口的实现类,用于封装表中的一条记录
    @Test
    public void testQuery1() throws SQLException {
        QueryRunner runner = new QueryRunner();
        Connection connection = JDBCUtil.getConnection3();
        String sql = "select id,name,email,birth from customers where id =? ";
        BeanHandler<Customer> handler = new BeanHandler<Customer>(Customer.class);
        Customer customer = runner.query(connection, sql, handler, 13);
        System.out.println(customer);
    }

    @Test
    public void testQuery2() throws SQLException {
        QueryRunner runner = new QueryRunner();
        Connection connection = JDBCUtil.getConnection3();
        String sql = "select id,name,email,birth from customers where id <? ";
        BeanListHandler<Customer> handler = new BeanListHandler<Customer>(Customer.class);
        List<Customer> customers = runner.query(connection, sql, handler, 13);
        customers.forEach(System.out::println);
    }

    @Test
    public void testQuery3() throws SQLException {
        QueryRunner runner = new QueryRunner();
        Connection connection = JDBCUtil.getConnection3();
        String sql = "select id,name,email,birth from customers where id =? ";
        MapHandler handler = new MapHandler();
        Map<String, Object> map = runner.query(connection, sql, handler, 13);
        System.out.println(map);
    }

    @Test
    public void test4() throws SQLException {
        QueryRunner runner = new QueryRunner();
        Connection connection = JDBCUtil.getConnection3();
        String sql = "select count(*) from customers";
        ScalarHandler h = new ScalarHandler();
        Long count = (Long) runner.query(connection, sql, h);
        System.out.println(count);
    }

    //自定义ResultSetHandler的类
    @Test
    public void test5() throws SQLException {
        QueryRunner runner = new QueryRunner();
        Connection connection = JDBCUtil.getConnection3();
        String sql = "select id,name,email,birth from customers where id =? ";
        ResultSetHandler<Customer> handler = new ResultSetHandler<>() {
            @Override
            public Customer handle(ResultSet resultSet) throws SQLException {
                if (resultSet.next()) {
                    int id = resultSet.getInt("id");
                    String name = resultSet.getString("name");
                    String email = resultSet.getString("email");
                    Date birth = resultSet.getDate("birth");
                    Customer customer = new Customer(id, name, email, birth);
                    return customer;
                }
                return null;
            }
        };
        Customer customer = runner.query(connection, sql, handler, 10);
        System.out.println(customer);

    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值