这里只是对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)]
当前光标在第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