jdbc快速入坑(二)

  这里只是对jdbc及进行简单的入门与使用,详细的教程戳这里,因为咱也是学人家的。OK,直接开整,项目代码地址:https://gitee.com/fluffycatkin/yyx-study-mybatis.git

  之前说到了JDBC操作数据库的六个步骤,下面对每个步骤的不同使用姿势都试一哈。

一、准备工作

  由于要对每个步骤分别进行测试,所以为了不重复写相同的代码,把前面的查询操作进行简单的封装一下。

  • 新建一个Jdbc操作数据库的模板类JdbcTemplate,封装了每个步骤:
package cn.fpg.mybatis.jdbc;

import cn.fpg.mybatis.pojo.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
//步骤1:导包
import java.sql.*;


/**
 * @program: yyx-study-mybatis
 * @description:
 * @author: fluffycatkin
 * @create: 2020-06-28 13:35
 **/
@Slf4j
public abstract class JdbcTemplate{

    static final String DRIVER = "com.mysql.cj.jdbc.Driver";
    static final String URL = "jdbc:mysql://127.0.0.1:3306/mybatis?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&serverTimezone=UTC";
    static final String USER_NAME = "root";
    static final String PASSWORD = "fluffycatkin";

    Connection connection = null;
    PreparedStatement preparedStatement = null;
    ResultSet resultSet = null;
    List<User> users = new ArrayList<>();


     void execTestQuery(){
        log.info("步骤1:导包.......JdbcTemplate....");
        registrationDriver();
        getConnection();
        createStatement();
        getResult();
        printResult();
        actionResult();
        close();
    }

    /**
     * 步骤2:注册驱动
     */
    protected abstract void registrationDriver();
    /**
     * 步骤3:获取链接
     */
    protected abstract void getConnection();


    /**
     * 步骤4:创建一个查询
     */
    protected abstract void createStatement();

    /**
     * 步骤5:获取数据,封装成实体类
     */
    protected abstract void getResult();


    private void printResult(){
        if (!CollectionUtils.isEmpty(users)){
            log.info("查询结果为:");
            System.out.println("-----------------所有数据-------------------");
            users.forEach(System.out::println);
            System.out.println("-----------------所有数据-------------------");
        }
    }

    /**
     * 对结果进行操作
     */
    protected abstract void actionResult();

    /**
     * 步骤6:释放资源
     */
    public void close()  {
        log.info(" 步骤6:释放资源.....");
        //保证资源被释放
        if (resultSet!=null){
            try {
                resultSet.close();
                log.info(" resultSet资源已释放.....");
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (preparedStatement!=null){
            try {
                preparedStatement.close();
                log.info(" preparedStatement资源已释放.....");
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (connection!=null){
            try {
                connection.close();
                log.info(" connection资源已释放.....");
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

  • 然后新建一个DefaultJdbc实现JdbcTemplate模板中的方法,所实现的功能就是之前的JdbcQuickStart类,对数据库进行简单的查询操作:
package cn.fpg.mybatis.jdbc;

import cn.fpg.mybatis.pojo.User;
import lombok.extern.slf4j.Slf4j;


import java.sql.*;
import java.util.List;


/**
 * @program: yyx-study-mybatis
 * @description: 帮助类,代码重用,测试的时候可以少写代码
 * @author: fluffycatkin
 * @create: 2020-06-28 12:26
 **/
@Slf4j
public  class DefaultJdbc extends JdbcTemplate {


    /**
     * 步骤2:注册驱动
     */
    @Override
    protected  void registrationDriver(){
        log.info("步骤2:注册驱动.......DefaultJdbc....");
        try {
            Class.forName(DRIVER);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    /**
     * 步骤3:获取链接
     */
    @Override
    protected void getConnection(){
        log.info("步骤3:获取链接.......DefaultJdbc....");
        try {
            connection = DriverManager.getConnection(URL,USER_NAME,PASSWORD);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }


    /**
     * 步骤4:创建一个查询
     */
    @Override
    protected void createStatement(){
        log.info("步骤4:创建查询.......DefaultJdbc....");
        String  sql = "SELECT * FROM user where user_name = ?";
        try {
            preparedStatement = connection.prepareStatement(sql);
            connection.createStatement();
            preparedStatement.setString(1,"张三");
            log.info("sql:"+preparedStatement.toString());

        } catch (SQLException e) {
            e.printStackTrace();
        }

    }

    /**
     * 步骤5:获取数据,封装成实体类
     */
    @Override
    protected void getResult(){
        log.info("步骤5:获取数据,封装成实体类.......DefaultJdbc....");
        try {
            resultSet = preparedStatement.executeQuery();
            handleRs(resultSet, users);
        } catch (SQLException e) {
            e.printStackTrace();
        }

    }

    static List<User> handleRs(ResultSet resultSet, List<User> users) throws SQLException {
        while (resultSet.next()){
            User user = new User();
            user.setId(resultSet.getInt("id"));
            user.setUserName(resultSet.getString("user_name"));
            user.setAge(resultSet.getInt("age"));
            users.add(user);
        }
        return users;
    }

    @Override
    protected void actionResult() {
    }
}
  • 然后新建一个测试类,所有的测试都在这个类中:
package cn.fpg.mybatis.jdbc;

import org.junit.Test;

/**
 * @program: yyx-study-mybatis
 * @description:
 * @author: fluffycatkin
 * @create: 2020-06-28 13:43
 **/
public class JdbcTest {


    @Test
    public void testDefault(){
        JdbcTemplate defaultJdbc = new DefaultJdbc();
        defaultJdbc.execTestQuery();
    }

    /*@Test
    public void testDriver(){
        JdbcTemplate testDriver = new TestDriver();
        testDriver.execTestQuery();
    }

    @Test
    public void testConnection(){
        JdbcTemplate testConnection = new TestConnection();
        testConnection.execTestQuery();
    }

    @Test
    public void testStatement(){
        JdbcTemplate testStatement = new TestStatement();
        testStatement.execTestQuery();
    }

    @Test
    public void testResultSet(){
        JdbcTemplate testResultSet = new TestResultSet();
        testResultSet.execTestQuery();
    }*/
}

  • OK,运行一下testDefault()方法,瞅瞅DefaultJdbc能否成功查询到数据库,若成功,则结果如下:
23:20:05.631 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate - 步骤1:导包.......JdbcTemplate....
23:20:05.633 [main] INFO cn.fpg.mybatis.jdbc.DefaultJdbc - 步骤2:注册驱动.......DefaultJdbc....
23:20:05.639 [main] INFO cn.fpg.mybatis.jdbc.DefaultJdbc - 步骤3:获取链接.......DefaultJdbc....
23:20:05.965 [main] INFO cn.fpg.mybatis.jdbc.DefaultJdbc - 步骤4:创建查询.......DefaultJdbc....
23:20:05.973 [main] INFO cn.fpg.mybatis.jdbc.DefaultJdbc - sql:com.mysql.cj.jdbc.ClientPreparedStatement: SELECT * FROM user where user_name = '张三'
23:20:05.973 [main] INFO cn.fpg.mybatis.jdbc.DefaultJdbc - 步骤5:获取数据,封装成实体类.......DefaultJdbc....
23:20:05.984 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate - 查询结果为:
-----------------所有数据-------------------
User(id=1, userName=张三, age=0)
-----------------所有数据-------------------
23:20:05.984 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate -  步骤6:释放资源.....
23:20:05.984 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate -  resultSet资源已释放.....
23:20:05.985 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate -  preparedStatement资源已释放.....
23:20:05.986 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate -  connection资源已释放.....

Process finished with exit code 0

  准备工作完成,接下来对每一步进行测试。第一步导包没啥好说的,直接从第二步【注册驱动】开始。

二、注册驱动的两种姿势

  在使用程序之前,必须先注册该驱动程序。这里注册MySql驱动,Oracl和SQL Server的驱动见jdbc快速入坑(一)

  • 通过Class.forName()注册,单纯的jdbc连接推荐使用这个方法,它将驱动程序的类文件动态加载到内存中,并将其自动注册。
  • 通过DriverManager.registerDriver()注册。
      什么?他俩有啥区别?来来,请移驾到这个大佬的博客:https://www.iteye.com/blog/xm-king-798331。

  下面分别使用两种方法注册驱动,创建一个TestDriver类,继承DefaultJdbc,然后重写registrationDriver()这个注册驱动的方法,在这个方法中分别调用registrationDriverWithDriverManager()方法和registrationDriverWithDefault()方法进行测试:

package cn.fpg.mybatis.jdbc;


import lombok.extern.slf4j.Slf4j;

import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;

/**
 * @Author Fluffy Catkin
 * @Date 2020/6/27 13:10
 * @Version 1.0
 * @Description 注册驱动的两种姿势
 */
@Slf4j
public class TestDriver extends DefaultJdbc {

    @Override
    protected  void registrationDriver(){
        this.registrationDriverWithDefault();
    }


    /**
     * 使用DriverManager 注册驱动
     */
    private  void registrationDriverWithDriverManager(){

        log.info("自定义步骤2:注册驱动.......TestDriver....registrationDriverWithDriverManager");
        try {
            Driver driver = new com.mysql.cj.jdbc.Driver();
            DriverManager.registerDriver(driver);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    /**
     * 使用 Class.forName(DRIVER) 注册驱动
     */
    private void registrationDriverWithDefault(){
        try {
            log.info("自定义步骤2:注册驱动.......TestDriver....registrationDriverWithDefault");
            Class.forName(DRIVER);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

}

  还记得JdbcTest这个专门用来测试的类不?把testDriver()方法放开,然后运行,就会发现不管用哪种方法注册驱动都可以成功。这就对了,其中一个的结果如下:

23:42:51.936 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate - 步骤1:导包.......JdbcTemplate....
23:42:51.938 [main] INFO cn.fpg.mybatis.jdbc.TestDriver - 自定义步骤2:注册驱动.......TestDriver....registrationDriverWithDefault
23:42:51.944 [main] INFO cn.fpg.mybatis.jdbc.DefaultJdbc - 步骤3:获取链接.......DefaultJdbc....
23:42:52.274 [main] INFO cn.fpg.mybatis.jdbc.DefaultJdbc - 步骤4:创建查询.......DefaultJdbc....
23:42:52.282 [main] INFO cn.fpg.mybatis.jdbc.DefaultJdbc - sql:com.mysql.cj.jdbc.ClientPreparedStatement: SELECT * FROM user where user_name = '张三'
23:42:52.282 [main] INFO cn.fpg.mybatis.jdbc.DefaultJdbc - 步骤5:获取数据,封装成实体类.......DefaultJdbc....
23:42:52.294 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate - 查询结果为:
-----------------所有数据-------------------
User(id=1, userName=张三, age=0)
-----------------所有数据-------------------
23:42:52.295 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate -  步骤6:释放资源.....
23:42:52.295 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate -  resultSet资源已释放.....
23:42:52.295 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate -  preparedStatement资源已释放.....
23:42:52.297 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate -  connection资源已释放.....

Process finished with exit code 0

三、获取连接的三种姿势

  说是三种姿势,其实就是DriverManager的一个静态方法getConnection()的三种多态形式,三种方法如下:

  • getConnection(String url)
  • getConnection(String url, Properties prop)
  • getConnection(String url, String user, String password)
      新建一个TestConnection类,继承DefaultJdbc并覆盖getConnection()获取连接的方法:
package cn.fpg.mybatis.jdbc;

import lombok.extern.slf4j.Slf4j;

import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;

/**
 * @program: yyx-study-mybatis
 * @description: 创建连接的几种姿势
 * @author: fluffycatkin
 * @create: 2020-06-28 14:32
 **/
@Slf4j
public class TestConnection extends DefaultJdbc{


    @Override
    protected void getConnection() {
      this.getConnectionWithOneParam();
    }

    /**
     * getConnection(String url)
     */
    private void getConnectionWithOneParam() {
        log.info("步骤3:获取链接.......TestConnection....getConnectionWithOneParam");
        try {
            String url = "jdbc:mysql://127.0.0.1:3306/mybatis?user=root&password=fluffycatkin&useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&serverTimezone=UTC";
            connection = DriverManager.getConnection(url);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    private void getConnectionWithTwoParams() {
        log.info("步骤3:获取链接.......TestConnection....getConnectionWithTwoParams");
        try {
            Properties properties = new Properties();
            properties.setProperty("user","root");
            properties.setProperty("password","123456");
            connection = DriverManager.getConnection(URL,properties);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    private void getConnectionWithThreeParams() {
        log.info("步骤3:获取链接.......TestConnection....getConnectionWithThreeParams");
        try {
            connection = DriverManager.getConnection(URL,USER_NAME,PASSWORD);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

  解开JdbcTest的testConnection()方法的注释,然后修改TestConnection类的getConnection()方法,使用不同的姿势进行测试,下面只给出其中一个的运行结果:

23:58:34.240 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate - 步骤1:导包.......JdbcTemplate....
23:58:34.242 [main] INFO cn.fpg.mybatis.jdbc.DefaultJdbc - 步骤2:注册驱动.......DefaultJdbc....
23:58:34.249 [main] INFO cn.fpg.mybatis.jdbc.TestConnection - 步骤3:获取链接.......TestConnection....getConnectionWithOneParam
23:58:34.571 [main] INFO cn.fpg.mybatis.jdbc.DefaultJdbc - 步骤4:创建查询.......DefaultJdbc....
23:58:34.579 [main] INFO cn.fpg.mybatis.jdbc.DefaultJdbc - sql:com.mysql.cj.jdbc.ClientPreparedStatement: SELECT * FROM user where user_name = '张三'
23:58:34.579 [main] INFO cn.fpg.mybatis.jdbc.DefaultJdbc - 步骤5:获取数据,封装成实体类.......DefaultJdbc....
23:58:34.588 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate - 查询结果为:
-----------------所有数据-------------------
User(id=1, userName=张三, age=0)
-----------------所有数据-------------------
23:58:34.588 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate -  步骤6:释放资源.....
23:58:34.588 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate -  resultSet资源已释放.....
23:58:34.588 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate -  preparedStatement资源已释放.....
23:58:34.590 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate -  connection资源已释放.....

四、执行sql语句的三种姿势

1、通过Statement对象

  用于对数据库进行通用访问,在运行时使用静态SQL语句时很有用。 Statement接口不能接受参数。

  • 创建Statement:
Statement statement = connection.createStatement();
  • 通过Statement执行sql的三个方法:
    boolean execute (String SQL): 如果可以检索到ResultSet对象,则返回一个布尔值true; 否则返回false。使用此方法执行SQLDDL语句或需要使用真正的动态SQL,可使用于执行创建数据库,创建表的SQL语句等等。
    int executeUpdate (String SQL): 返回受SQL语句执行影响的行数。使用此方法执行预期会影响多行的SQL语句,例如:INSERT,UPDATE或DELETE语句。
    ResultSet executeQuery(String SQL):返回一个ResultSet对象。 当您希望获得结果集时,请使用此方法,就像使用SELECT语句一样。
  • 创建TestStatement类进行测试:
package cn.fpg.mybatis.jdbc;

import lombok.extern.slf4j.Slf4j;

import java.sql.CallableStatement;
import java.sql.SQLException;
import java.sql.Statement;


/**
 * @program: yyx-study-mybatis
 * @description: 创建查询的几种姿势
 * @author: fluffycatkin
 * @create: 2020-06-28 17:47
 *
 *
 **/
@Slf4j
public class TestStatement extends DefaultJdbc{


    @Override
    protected void createStatement() {
        this.createByStatement();
    }

    /**
     * 使用Statement进行插入、修改、查询操作
     */
    private void createByStatement(){
        try {
            Statement statement = connection.createStatement();
            String  sqlInsert = "INSERT INTO user(user_name) VALUES ('李四')";
            String  sqlUpdate = "UPDATE user set user_name = '王五' where user_name = '李四'";
            String  sqlSelect = "SELECT * FROM user where user_name = '王五'";
            //插入操作
            int insertRes = statement.executeUpdate(sqlInsert);

            log.info("插入成功,插入的条数为:........"+insertRes);

            //修改操作
            int updateNum = statement.executeUpdate(sqlUpdate);
            log.info("修改成功,修改的条数为:"+updateNum);
            //查询操作
            resultSet = statement.executeQuery(sqlSelect);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    /**
     * 使用PreparedStatement进行查询操作
     */
    private void createByPreparedStatement(){
        log.info("步骤4:创建查询.......TestStatement....createByPreparedStatement");
        super.createStatement();
        try {
            resultSet = preparedStatement.executeQuery();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    /**
     * 使用CallableStatement执行存储过程
     */
    private void createByCallableStatement(){
        //创建一个存储过程
        /*DELIMITER $$

        DROP PROCEDURE IF EXISTS `mybatis`.`getUserName` $$
        CREATE PROCEDURE `mybatis`.`getUserName`
        (IN ID INT, OUT USER_NAME VARCHAR(255))
        BEGIN
         SELECT  u.USER_NAME  INTO USER_NAME
           FROM USER u
           WHERE u.ID = ID LIMIT 1;
        END $$

        DELIMITER ;*/
        log.info("步骤4:创建查询.......TestStatement....createByCallableStatement");
        String sql = "{call getUserName (?, ?)}";
        try {
            CallableStatement callableStatement = connection.prepareCall(sql);
            callableStatement.setInt(1,1);
            callableStatement.registerOutParameter(2, java.sql.Types.VARCHAR);
            callableStatement.executeQuery();
            String userName = callableStatement.getString(2);
            System.out.println("获取到用户姓名为:"+userName);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }


    /**
     * 步骤5:获取数据,封装成实体类
     */
    @Override
    protected void getResult(){
        try {
            if (resultSet!=null){
                log.info("步骤5:获取数据,封装成实体类.......TestStatement....");
                handleRs(resultSet, users);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }

    }
}

  • 执行JdbcTest的testStatement()方法,调用TestConnection的createByStatement()方法,结果如下:
00:17:12.802 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate - 步骤1:导包.......JdbcTemplate....
00:17:12.804 [main] INFO cn.fpg.mybatis.jdbc.DefaultJdbc - 步骤2:注册驱动.......DefaultJdbc....
00:17:12.810 [main] INFO cn.fpg.mybatis.jdbc.DefaultJdbc - 步骤3:获取链接.......DefaultJdbc....
00:17:13.178 [main] INFO cn.fpg.mybatis.jdbc.TestStatement - 插入成功,插入的条数为:........1
00:17:13.219 [main] INFO cn.fpg.mybatis.jdbc.TestStatement - 修改成功,修改的条数为:1
00:17:13.227 [main] INFO cn.fpg.mybatis.jdbc.TestStatement - 步骤5:获取数据,封装成实体类.......TestStatement....
00:17:13.228 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate - 查询结果为:
-----------------所有数据-------------------
User(id=12, userName=王五, age=0)
-----------------所有数据-------------------
00:17:13.229 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate -  步骤6:释放资源.....
00:17:13.229 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate -  resultSet资源已释放.....
00:17:13.230 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate -  connection资源已释放.....

Process finished with exit code 0
2、通过PreparedStatement对象

  当计划要多次使用SQL语句时使用。PreparedStatement接口在运行时接受输入参数。

  • 创建PreparedStatement对象
preparedStatement = connection.prepareStatement(sql);
  • 有如下几点:
    ① JDBC中的所有参数都由 ? 符号作为占位符,这被称为参数标记。 在执行SQL语句之前,必须为每个参数(占位符)提供值。
    ② setXXX()方法将值绑定到参数,其中XXX表示要绑定到输入参数的值的Java数据类型。 如果忘记提供绑定值,则将会抛出一个SQLException。
    ③ 每个参数标记是它其顺序位置引用。第一个标记表示位置1,下一个位置2等等。 该方法与Java数组索引不同(它不从0开始)。
    ④ 所有Statement对象与数据库交互的方法(a)execute(),(b)executeQuery()和©executeUpdate()也可以用于PreparedStatement对象。 但是,这些方法被修改为可以使用输入参数的SQL语句。
  • 执行JdbcTest的testStatement()方法,调用TestConnection的createByPreparedStatement()方法,结果如下:
00:24:18.420 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate - 步骤1:导包.......JdbcTemplate....
00:24:18.422 [main] INFO cn.fpg.mybatis.jdbc.DefaultJdbc - 步骤2:注册驱动.......DefaultJdbc....
00:24:18.429 [main] INFO cn.fpg.mybatis.jdbc.DefaultJdbc - 步骤3:获取链接.......DefaultJdbc....
00:24:18.742 [main] INFO cn.fpg.mybatis.jdbc.TestStatement - 步骤4:创建查询.......TestStatement....createByPreparedStatement
00:24:18.742 [main] INFO cn.fpg.mybatis.jdbc.DefaultJdbc - 步骤4:创建查询.......DefaultJdbc....
00:24:18.749 [main] INFO cn.fpg.mybatis.jdbc.DefaultJdbc - sql:com.mysql.cj.jdbc.ClientPreparedStatement: SELECT * FROM user where user_name = '张三'
00:24:18.758 [main] INFO cn.fpg.mybatis.jdbc.TestStatement - 步骤5:获取数据,封装成实体类.......TestStatement....
00:24:18.760 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate - 查询结果为:
-----------------所有数据-------------------
User(id=1, userName=张三, age=0)
-----------------所有数据-------------------
00:24:18.760 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate -  步骤6:释放资源.....
00:24:18.760 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate -  resultSet资源已释放.....
00:24:18.761 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate -  preparedStatement资源已释放.....
00:24:18.762 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate -  connection资源已释放.....

Process finished with exit code 0
3、通过CallableStatement对象

 &emso;CallableStatement主要用于执行对数据库存储过程的调用。

  • 创建CallableStatement
CallableStatement callableStatement = connection.prepareCall(sql);
  • 创建一个存储过程:
DELIMITER $$

        DROP PROCEDURE IF EXISTS `mybatis`.`getUserName` $$
        CREATE PROCEDURE `mybatis`.`getUserName`
        (IN ID INT, OUT USER_NAME VARCHAR(255))
        BEGIN
         SELECT  u.USER_NAME  INTO USER_NAME
           FROM USER u
           WHERE u.ID = ID LIMIT 1;
        END $$

 DELIMITER ;
  • 执行JdbcTest的testStatement()方法,调用TestConnection的createByCallableStatement()方法,结果如下:
00:31:04.251 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate - 步骤1:导包.......JdbcTemplate....
00:31:04.253 [main] INFO cn.fpg.mybatis.jdbc.DefaultJdbc - 步骤2:注册驱动.......DefaultJdbc....
00:31:04.260 [main] INFO cn.fpg.mybatis.jdbc.DefaultJdbc - 步骤3:获取链接.......DefaultJdbc....
00:31:04.574 [main] INFO cn.fpg.mybatis.jdbc.TestStatement - 步骤4:创建查询.......TestStatement....createByCallableStatement
获取到用户姓名为:张三
00:31:04.601 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate -  步骤6:释放资源.....
00:31:04.602 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate -  connection资源已释放.....

Process finished with exit code 0

五、对结果集进行操作

  对结果集操作的方法的介绍:https://www.yiibai.com/jdbc/jdbc-result-sets.html
  下面 创建TestResultSet进行测试:

package cn.fpg.mybatis.jdbc;

import cn.fpg.mybatis.pojo.User;
import lombok.extern.slf4j.Slf4j;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * @program: yyx-study-mybatis
 * @description: 测试结果集处理
 * @author: fluffycatkin
 * @create: 2020-07-06 10:09
 **/
@Slf4j
public class TestResultSet extends DefaultJdbc{

    /**
     * 步骤4:创建一个查询
     */
    @Override
    protected void createStatement(){
        log.info("步骤4:创建查询.......DefaultJdbc....");
        String  sql = "SELECT * FROM user";
        try {
            // 对于第二个参数resultSetType:
            //      TYPE_FORWARD_ONLY:光标只能在结果集中向前移动。
            //      TYPE_SCROLL_INSENSITIVE:光标可以向前和向后滚动,结果集对创建结果集后发生的数据库所做的更改不敏感。
            //      TYPE_SCROLL_SENSITIVE:光标可以向前和向后滚动,结果集对创建结果集之后发生的其他数据库的更改敏感。
            // 对于第三个参数resultSetConcurrency:
            //      CONCUR_READ_ONLY :创建只读结果集,这是默认值。
            //      CONCUR_UPDATABLE:创建可更新的结果集
            preparedStatement = connection.prepareStatement(sql, ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
            connection.createStatement();
            log.info("sql:"+preparedStatement.toString());
        } catch (SQLException e) {
            e.printStackTrace();
        }

    }


    @Override
    protected void actionResult() {
        log.info("对结果进行操作:");
        try {
            System.out.println("------------------action-------------------");
            //将光标移动到第一行之前位置
            resultSet.beforeFirst();
            this.printUserOneLine("第一行之前");

            //将光标移动到最后一行之后
            resultSet.afterLast();
            this.printUserOneLine("最后一行之后");

            //将光标移动到最后一行
            resultSet.last();
            this.printUserOneLine("最后一行");

            //将光标移动到第一行
            resultSet.first();
            this.printUserOneLine("第一行");

            //将光标移动到指定行,第三行
            resultSet.absolute(3);
            this.printUserOneLine("指定行,第三行");

            //从当前指向的位置,将光标向前或向后移动给定行数。
            //向前移动一行
            resultSet.relative(2);
            this.printUserOneLine("向前两行");
            //向后移动一行
            resultSet.relative(-1);
            this.printUserOneLine("向后一行");

            //将光标移动到上一行。 如果上一行关闭结果集,此方法返回false。
            resultSet.previous();
            this.printUserOneLine("上一行");

            //将光标移动到下一行。 如果结果集中没有更多行,则此方法返回false。
            resultSet.next();
            this.printUserOneLine("下一行");

            //返回光标指向的行号。
            int rowNum = resultSet.getRow();
            System.out.println(String.format("当前光标在第%s行",rowNum));

            //对结果集进行修改并同步到数据库
            log.info("对结果集进行修改并同步到数据库....");
            resultSet.beforeFirst();
            int ageAdd = 1;
            while(resultSet.next()){
                int newAge = resultSet.getInt("age") + ageAdd;
                //通过字段修改年龄
                resultSet.updateInt( "age", newAge );
                //通过字段下标修改姓名,下标从1开始
                resultSet.updateString(2,resultSet.getString("user_name")+"_千百年后,风采依旧");
                //更新数据库中当前行
                resultSet.updateRow();
                ageAdd++;
            }

            System.out.println("--修改后的数据为:--");
            resultSet.beforeFirst();
            List<User> afterUpdateUsers = handleRs(resultSet,  new ArrayList<>());
            afterUpdateUsers.forEach(System.out::println);
            System.out.println("--修改后的数据end--");


            log.info("在结果集中新增一条数据,并同步到数据库...");
            resultSet.moveToInsertRow();
            resultSet.updateString("user_name","盘古");
            resultSet.updateInt("age",9999);
            resultSet.insertRow();

            System.out.println("--新增后的数据为:--");
            resultSet.beforeFirst();
            List<User> afterInsertUsers = handleRs(resultSet, new ArrayList<>());
            afterInsertUsers.forEach(System.out::println);
            System.out.println("--新增后的数据end--");


            log.info("在结果集中删除一条数据,并同步到数据库...");

            //将光标移动到第二行
            resultSet.absolute(2);
            System.out.println(String.format("要删除的行为:[User(id = %s, userName = %s, age = %s)]",
                    resultSet.getInt("id"), resultSet.getString("user_name"),resultSet.getInt("age")));
            //删除这行
            resultSet.deleteRow();

            System.out.println("--删除后的数据为:--");
            resultSet.beforeFirst();
            List<User> afterDeleteUsers = handleRs(resultSet, new ArrayList<>());
            afterDeleteUsers.forEach(System.out::println);
            System.out.println("--删除后的数据end--");

            System.out.println("------------------action-------------------");
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    private void printUserOneLine(String message ){
        try {
            //判断光标是否在最后一行之后
            if (resultSet.isAfterLast()){
                System.out.println(String.format("光标位置在:%s",message));
                return;
            }
            //判断光标是否在第一行之前
            if (resultSet.isBeforeFirst()){
                System.out.println(String.format("光标位置在:%s",message));
                return;
            }
            int id = resultSet.getInt("id");
            String userName = resultSet.getString("USER_NAME");
            String age = resultSet.getString("age");
            System.out.println(String.format("光标移动到%s后:[User(id = %s, userName = %s, age = %s)]",message, id, userName,age));
        } catch (SQLException e) {
           e.printStackTrace();
        }

    }
}

  • 执行JdbcTest中的testResultSet()方法,结果如下:
00:46:56.897 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate - 步骤1:导包.......JdbcTemplate....
00:46:56.898 [main] INFO cn.fpg.mybatis.jdbc.DefaultJdbc - 步骤2:注册驱动.......DefaultJdbc....
00:46:56.905 [main] INFO cn.fpg.mybatis.jdbc.DefaultJdbc - 步骤3:获取链接.......DefaultJdbc....
00:46:57.216 [main] INFO cn.fpg.mybatis.jdbc.TestResultSet - 步骤4:创建查询.......DefaultJdbc....
00:46:57.224 [main] INFO cn.fpg.mybatis.jdbc.TestResultSet - sql:com.mysql.cj.jdbc.ClientPreparedStatement: SELECT * FROM user
00:46:57.224 [main] INFO cn.fpg.mybatis.jdbc.DefaultJdbc - 步骤5:获取数据,封装成实体类.......DefaultJdbc....
00:46:57.239 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate - 查询结果为:
-----------------所有数据-------------------
User(id=1, userName=张三, age=0)
User(id=6, userName=王羲之, age=0)
User(id=7, userName=李大白, age=0)
User(id=10, userName=武大郎, age=0)
User(id=11, userName=女娲, age=0)
User(id=12, userName=王五, age=0)
-----------------所有数据-------------------
00:46:57.240 [main] INFO cn.fpg.mybatis.jdbc.TestResultSet - 对结果进行操作:
------------------action-------------------
光标位置在:第一行之前
光标位置在:最后一行之后
光标移动到最后一行后:[User(id = 12, userName = 王五, age = 0)]
光标移动到第一行后:[User(id = 1, userName = 张三, age = 0)]
光标移动到指定行,第三行后:[User(id = 7, userName = 李大白, age = 0)]
光标移动到向前两行后:[User(id = 11, userName = 女娲, age = 0)]
光标移动到向后一行后:[User(id = 10, userName = 武大郎, age = 0)]
光标移动到上一行后:[User(id = 7, userName = 李大白, age = 0)]
光标移动到下一行后:[User(id = 10, userName = 武大郎, age = 0)]
当前光标在第400:46:57.242 [main] INFO cn.fpg.mybatis.jdbc.TestResultSet - 对结果集进行修改并同步到数据库....
--修改后的数据为:--
User(id=1, userName=张三_千百年后,风采依旧, age=1)
User(id=6, userName=王羲之_千百年后,风采依旧, age=2)
User(id=7, userName=李大白_千百年后,风采依旧, age=3)
User(id=10, userName=武大郎_千百年后,风采依旧, age=4)
User(id=11, userName=女娲_千百年后,风采依旧, age=5)
User(id=12, userName=王五_千百年后,风采依旧, age=6)
--修改后的数据end--
00:46:57.512 [main] INFO cn.fpg.mybatis.jdbc.TestResultSet - 在结果集中新增一条数据,并同步到数据库...
--新增后的数据为:--
User(id=1, userName=张三_千百年后,风采依旧, age=1)
User(id=6, userName=王羲之_千百年后,风采依旧, age=2)
User(id=7, userName=李大白_千百年后,风采依旧, age=3)
User(id=10, userName=武大郎_千百年后,风采依旧, age=4)
User(id=11, userName=女娲_千百年后,风采依旧, age=5)
User(id=12, userName=王五_千百年后,风采依旧, age=6)
User(id=14, userName=盘古, age=9999)
--新增后的数据end--
00:46:57.570 [main] INFO cn.fpg.mybatis.jdbc.TestResultSet - 在结果集中删除一条数据,并同步到数据库...
要删除的行为:[User(id = 6, userName = 王羲之_千百年后,风采依旧, age = 2)]
--删除后的数据为:--
User(id=1, userName=张三_千百年后,风采依旧, age=1)
User(id=7, userName=李大白_千百年后,风采依旧, age=3)
User(id=10, userName=武大郎_千百年后,风采依旧, age=4)
User(id=11, userName=女娲_千百年后,风采依旧, age=5)
User(id=12, userName=王五_千百年后,风采依旧, age=6)
User(id=14, userName=盘古, age=9999)
--删除后的数据end--
------------------action-------------------
00:46:57.621 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate -  步骤6:释放资源.....
00:46:57.622 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate -  resultSet资源已释放.....
00:46:57.622 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate -  preparedStatement资源已释放.....
00:46:57.626 [main] INFO cn.fpg.mybatis.jdbc.JdbcTemplate -  connection资源已释放.....

Process finished with exit code 0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值