这里只是对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:注册驱动*/@Overrideprotected  void registrationDriver(){log.info("步骤2:注册驱动.......DefaultJdbc....");try {Class.forName(DRIVER);} catch (ClassNotFoundException e) {e.printStackTrace();}}/*** 步骤3:获取链接*/@Overrideprotected void getConnection(){log.info("步骤3:获取链接.......DefaultJdbc....");try {connection = DriverManager.getConnection(URL,USER_NAME,PASSWORD);} catch (SQLException e) {e.printStackTrace();}}/*** 步骤4:创建一个查询*/@Overrideprotected 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:获取数据,封装成实体类*/@Overrideprotected 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;}@Overrideprotected 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 {@Testpublic void testDefault(){JdbcTemplate defaultJdbc = new DefaultJdbc();defaultJdbc.execTestQuery();}/*@Testpublic void testDriver(){JdbcTemplate testDriver = new TestDriver();testDriver.execTestQuery();}@Testpublic void testConnection(){JdbcTemplate testConnection = new TestConnection();testConnection.execTestQuery();}@Testpublic void testStatement(){JdbcTemplate testStatement = new TestStatement();testStatement.execTestQuery();}@Testpublic 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 {@Overrideprotected  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{@Overrideprotected 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{@Overrideprotected 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))BEGINSELECT  u.USER_NAME  INTO USER_NAMEFROM USER uWHERE 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:获取数据,封装成实体类*/@Overrideprotected 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))BEGINSELECT  u.USER_NAME  INTO USER_NAMEFROM USER uWHERE 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:创建一个查询*/@Overrideprotected 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();}}@Overrideprotected 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)]
当前光标在第4行
00: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

jdbc快速入坑(二)相关推荐

  1. 外包实习生怎么快速入坑--10K

    随着市场的变化,现在学历和工作经验要求越来越高,对于初步混工作经验的本科毕业生来说,往往前一年做实习生是比较好的选择. 如果刚起步,也没有非常牛逼的潜质,对于那些高智商,对技术有非常流弊钻研的人,当然 ...

  2. GIS开发入坑(二)--ArcGIS影像切片并使用GeoServer发布

    目录 1.使用ArcGIS切片 1.1修改ArcMap选项 1.2创建切片缓存方案 1.3开始切片 2.使用GeoServer发布切片缓存 2.1 启用GeoWebcache 2.2 发布切片 Geo ...

  3. 资源 |“从蒙圈到入坑”,推荐新一波ML、DL、RL以及数学基础等干货资源

    向AI转型的程序员都关注了这个号☝☝☝ 编译 | AI科技大本营(rgznai100) 参与 | suiling 此前营长曾发过一篇高阅读量.高转发率,高收藏量的文章<爆款 | Medium上6 ...

  4. PyTorch入坑(一)~(三): Tensor的概念,基本操作和线性回归

    PyTorch 一文入门 PyTorch 入坑一:数据类型与Tensor的概念 PyTorch数据类型 Tensor的概念 Tensor与Variable Variable Tensor Tensor ...

  5. 向量数据库入坑:使用 Docker 和 Milvus 快速构建本地轻量图片搜索引擎

    本篇文章,我来分享如何使用 Docker 来搭建一个能够跑在本地的轻量图片搜索引擎,实现日常生活中我们习以为常,但是实现起来颇为麻烦的功能:以图搜图. 写在前面 之前网上看到一个问题<如何在自己 ...

  6. 微信小程序从入坑到放弃二十二:完美兼容安卓和ios手机的底部评论框

    摘要: 不管是在普通的H5页面还是在微信小程序中,底部输入框一直是一大难题,因为键盘会在某些情况下遮挡信输入框一部分!值得庆幸的是:在微信小程序中,我们可以通过监听bindfocus来获取键盘的高度, ...

  7. DIY NAS服务器之OMV 5.6入坑指南(二)- 安装omv-extras插件

    系列文章目录 DIY NAS服务器之OMV 5.6入坑指南(一)-openmediavalut 5.6安装 DIY NAS服务器之OMV 5.6入坑指南(二)- 安装omv-extras插件 DIY ...

  8. 微信小程序入坑教程二十一:使用wx.saveImageToPhotosAlbum保存图片时通过检测scope.writePhotosAlbum权限来提醒用户是否需要授权

    摘要: 在昨天的文章<微信小程序入坑教程二十:生成海报前使用wx.downloadFile或wx.getImageInfo时潜在的坑>中提到了用户授权一事,scope.writePhoto ...

  9. 微信小程序从入坑到放弃二十九:一个小场景搞懂冒泡事件bindtap和catchtap的区别

    摘要: 在微信小程序中,bindtap事件会产生冒泡,若不加以拦截,会一直冒泡到顶端.在某些情况下,一次点击会触发若干点击事件.为了防止冒泡,使用catchtap即可解决问题.在有全屏半透明背景的弹出 ...

最新文章

  1. java map 输入 查询 修改_Mybatis增删改查mapper文件写法详解
  2. 分享SSRF漏洞的学习和利用
  3. idea中查看类中所有方法列表(Alt+7)(亲测)
  4. 电销机器人价格_箭鱼电销机器人:为什么电话机器人公司不用机器人给你打电话?...
  5. 计算机体系结构----常见英文缩写(待更....)
  6. C++ AFX_MANAGE_STATE(AfxGetStaticModuleState())的作用
  7. iphone-common-codes-ccteam源代码 CCUINavigationBar.h
  8. 经典最优滤波器(概述)
  9. [Swift]LeetCode480. 滑动窗口中位数 | Sliding Window Median
  10. ajax用iframe,使用ajax Post请求更新iframe内容
  11. python课程价格-python课程价格
  12. SSH Mybatis 框架
  13. Linux学习笔记之秋水BBR一键部署
  14. SK Comms信息外泄事件使韩国企业开始提高安全预算
  15. 计算机内 云盘图标,如何关闭我的电脑中百度网盘图标
  16. cocos2dx fnt字体、自定义字体制作(转载、记录、待验证)
  17. 彩钢板进行BS 476-3屋顶外露部分防火测试
  18. linux优化deepin启动速度,如何优化 Deepin 引导开机速度?
  19. 利用Flourish制作动态条形图
  20. 简单了解实体框架EF(Entity Framework)

热门文章

  1. Nginx——nginx作为静态资源web服务(CDN场景)
  2. MT8665芯片处理器,MT8665模块方案开发
  3. 英特奇android刷机,英特奇E88线刷刷机教程_英特奇E88线刷rom包_系统刷机包
  4. 人脸识别数据安全要求
  5. SpringMVC+Vue实现前后端的志愿者招募网站
  6. 虚荣 VG API 分析
  7. Python123 练习7
  8. 如何设置app字体跟随系统_Android 应用全局字体调节或禁止随系统字体大小更改...
  9. SAP License:反记账功能的应用
  10. 各种邮箱收发服务器地址及端口