Java SE 07(JDBC、数据库连接池、Spring中的JdbcTemplate类)
Java SE 07
一、JDBC
JDBC概述
-
JDBC(Java Database Connectivity),全称Java数据库连接,就是使用Java语言操作数据库
-
JDBC本质:是官方定义的一套操作所有关系型数据库的规则,即接口。各个数据库厂商去实现这套接口,提供数据库驱动jar包。开发者可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类
-
JDBC使用步骤:
-
导入驱动jar包mysql-connector-java-5.1.37-bin.jar
idea中操作步骤:
1 复制jar包到项目目录下的自定义文件夹下
2 右键这个文件夹add as library
-
注册驱动
-
获取数据库连接对象Connection
-
定义sql
-
获取执行sql语句的对象Statement
-
执行sql,接收返回结果
-
处理结果
-
释放资源
public class JdbcDemo01 { public static void main(String[] args) throws SQLException, ClassNotFoundException { //注册驱动jar包,在MySQL5之后可省略不写,原因:在jar包中META-INF文件夹中services下Driver类中有注册驱动jar包com.mysql.jdbc.Driver Class.forName("com.mysql.jdbc.Driver"); Connection cnn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db2", "root", "root"); Statement stmt = cnn.createStatement(); String sql = "UPDATE emp SET dept_id = 10 WHERE id = 1001"; int count = stmt.executeUpdate(sql); System.out.println(count); stmt.close(); cnn.close(); } }
代码中的各个对象:
-
DriverManager:驱动管理对象
功能:
-
注册驱动
DriverManager中的静态方法
static void registerDriver(Driver driver)
使用DriverManager注册给定的驱动程序在com.mysql.jdbc.Driver的源码中有静态代码块,使用
Class.forName
会将该类加载,同时执行这个静态代码块,从而完成驱动的注册static { try { java.sql.DriverManager.registerDriver(new Driver()); } catch (SQLException E) { throw new RuntimeException("Can't register driver!"); } }
-
获取数据库连接
DriverManager中的静态方法
static Connection getConnection(String url, String user, String password)
方法参数:url:指定连接的路径, user:用户名,password:密码
url的格式:
jdbc:mysql://ip地址(域名):端口号/数据库名称
如果连接的是本机mysql服务器,并且mysql服务默认端口是3306,
url可以简写为
jdbc:mysql:///数据库名称
-
-
Connection:数据库连接对象
Connection类中的方法
-
获取执行sql的对象
Statement createStatement()
PreparedStatement prepareStatement(Stirng sql)
-
管理事务
-
开启事务
setAutoCommit(boolean autocommit)
调用该方法设置参数为false,就是开启事务
-
提交事务
commit()
-
回滚事务
rollback()
-
-
-
Statement:执行sql的对象
Statement类中的方法
-
boolean execuate(String sql)
可以执行任意的sql -
int execuateUpdate(String sql)
执行DML(常用)、DDL(不常用)若传入DML的返回值:sql语句执行后影响的行数,可以通过这个影响的行数判断DML语句是否执行成功,返回值>0执行成功,否则执行失败。若传入的是DDL则return nothing
-
ResultSet executeQuery(String sql)
执行DQL语句(select)
-
-
ResultSet:结果集对象
-
PreparedStatement:执行sql的对象
-
JDBC中使用insert语句
-
示例Code
public class JdbcDemo02 { public static void main(String[] args) { Statement stat = null; Connection conn = null; try { Class.forName("com.mysql.jdbc.Driver"); String sql = "INSERT INTO emp VALUES (1016, 'Jeff', 3, 1004, '2021-7-5', 9000, null, 30)"; conn = DriverManager.getConnection("jdbc:mysql:///db2", "root", "root"); stat = conn.createStatement(); int num = stat.executeUpdate(sql); if(num > 0) { System.out.println("insert successfully!"); } else { System.out.println("fail to insert!"); } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); //这里使用finally来释放资源,不管try中的程序是否正常执行,最终到这里会释放资源 } finally { //若try中的程序没有正常释放资源,这里的引用类型的对象值仍为null,所以先判断防止空指针异常 if(stat != null) { try { stat.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(conn != null) { try { conn.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } } } } /*output:在数据库db2的emp表中成功地插入了一条指定的数据 insert successfully! */
JDBC中使用update语句
-
示例Code
//方法同上,只是改变了sql语句 public class JdbcDemo03 { public static void main(String[] args) { Statement stat = null; Connection conn = null; try { Class.forName("com.mysql.jdbc.Driver"); String sql = "UPDATE emp SET ename = 'Jack' WHERE id = 1016"; conn = DriverManager.getConnection("jdbc:mysql:///db2", "root", "root"); stat = conn.createStatement(); int count = stat.executeUpdate(sql); if(count > 0) { System.out.println("update successfully!"); } else { System.out.println("fail to update!"); } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } finally { if(stat != null) { try { stat.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(conn != null) { try { conn.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } } } } /*output:在数据库db2的emp表中成功地修改了一条指定的字段值 update successfully! */
JDBC中使用delete语句
-
示例Code
//方法同上,只是改变了sql语句 public class JdbcDemo04 { public static void main(String[] args) { Statement stat = null; Connection conn = null; try { Class.forName("com.mysql.jdbc.Driver"); String sql = "DELETE FROM emp WHERE id = 1016"; conn = DriverManager.getConnection("jdbc:mysql:///db2", "root", "root"); stat = conn.createStatement(); int count = stat.executeUpdate(sql); if(count > 0) { System.out.println("delete successfully!"); } else { System.out.println("fail to delete!"); } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } finally { if(stat != null) { try { stat.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(conn != null) { try { conn.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } } } } /*output:在数据库db2的emp表中成功地删除了一条指定的数据 delete successfully! */
JDBC中使用DDL语句
-
示例Code
//方法几乎与上面例子,只是改变了sql语句 //去除了executeUpdate方法的返回值判断,因为此时传入的参数是DDL的sql,返回nothing public class JdbcDemo05 { public static void main(String[] args) { Statement stat = null; Connection conn = null; try { Class.forName("com.mysql.jdbc.Driver"); String sql = "CREATE TABLE tab_test(id INT, name VARCHAR(32))"; conn = DriverManager.getConnection("jdbc:mysql:///db2", "root", "root"); stat = conn.createStatement(); int count = stat.executeUpdate(sql); System.out.println("count = " + count); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } finally { if(stat != null) { try { stat.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(conn != null) { try { conn.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } } } } /*output:在数据库db2中创建新表tab_test count = 0 */
ResultSet类
-
通过Statement类的executeQuery方法返回ResultSet类的对象
ResultSet executeQuery(String sql)
执行DQL语句(select) -
ResultSet类中的方法
-
boolean next()
:游标向下移动一行,判断当前行是否是最后一行的末尾(是否有数据),如果是返回false,如果不是返回true使用步骤:
- 游标向下移动一行
- 判断是否有数据
- 获取数据
-
getXxx(args)
:获取数据Xxx代表数据类型,如
int getInt()
,String getString()
args参数:
(1) int:代表列的编号,从1开始,如:
getString(1)
(2) String:代表列的名称,如:getDouble(balance)
-
-
示例Code
//代码几乎同上面的例子,使用executeQuery方法返回ResultSet对象 public class JdbcDemo06 { public static void main(String[] args) { Statement stat = null; Connection conn = null; ResultSet rs = null; try { Class.forName("com.mysql.jdbc.Driver"); String sql = "SELECT * FROM emp"; conn = DriverManager.getConnection("jdbc:mysql:///db2", "root", "root"); stat = conn.createStatement(); rs = stat.executeQuery(sql); //使用ResultSet类的方法,获取表中的数据 rs.next(); int id = rs.getInt(1); String name = rs.getString(2); System.out.println("id = " + id + ", name = " + name); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } finally { //释放创建ResultSet类对象所需的资源 if(rs != null) { try { rs.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(stat != null) { try { stat.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(conn != null) { try { conn.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } } } } /*output: 显示查询到的表中的一行信息 */
public class JdbcDemo07 { public static void main(String[] args) { Statement stat = null; Connection conn = null; ResultSet rs = null; try { Class.forName("com.mysql.jdbc.Driver"); String sql = "SELECT * FROM emp"; conn = DriverManager.getConnection("jdbc:mysql:///db2", "root", "root"); stat = conn.createStatement(); rs = stat.executeQuery(sql); while(rs.next()) { int id = rs.getInt(1); String name = rs.getString(2); System.out.println("id = " + id + ", name = " + name); } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } finally { if(rs != null) { try { rs.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(stat != null) { try { stat.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(conn != null) { try { conn.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } } } } /*output: 显示查询到的表中的多行信息(指定的几列,循环遍历打印) */
JDBC实例
-
定义一个方法,查询emp表的数据将其封装为对象,然后装载集合,返回
-
实现步骤:
1 定义Emp类
2 定义方法public List<Emp> getAllInfo(){}
3 使用的sql语句select * from emp;
-
实例Code
//将数据库表emp中的字段,作为Emp表这个类的各个成员变量 public class Emp { private int id; private String eName; private int job_id; private int mgr; private Date date; private double salary; private double bonus; private int dept_id; public Emp() { } @Override public String toString() { return "emp{" + "id=" + id + ", eName='" + eName + '\'' + ", job_id=" + job_id + ", mgr=" + mgr + ", date=" + date + ", salary=" + salary + ", bonus=" + bonus + ", dept_id=" + dept_id + '}'; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String geteName() { return eName; } public void seteName(String eName) { this.eName = eName; } public int getJob_id() { return job_id; } public void setJob_id(int job_id) { this.job_id = job_id; } public int getMgr() { return mgr; } public void setMgr(int mgr) { this.mgr = mgr; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } public double getBonus() { return bonus; } public void setBonus(double bonus) { this.bonus = bonus; } public int getDept_id() { return dept_id; } public void setDept_id(int dept_id) { this.dept_id = dept_id; } }
public class JdbcDemo08 { public static void main(String[] args) { JdbcDemo08 jdbcDemo08 = new JdbcDemo08(); List<Emp> allInfo = jdbcDemo08.getAllInfo(); //System.out.println(allInfo); for(Emp ele : allInfo) { System.out.println(ele); } } public List<Emp> getAllInfo() { List<Emp> list = new ArrayList<>(); Connection conn = null; Statement stmt = null; ResultSet resultSet = null; try { Class.forName("com.mysql.jdbc.Driver"); conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db2","root", "root"); stmt = conn.createStatement(); String sql = "SELECT * FROM emp"; resultSet = stmt.executeQuery(sql); Emp emp = null; while(resultSet.next()) { emp = new Emp(); int id = resultSet.getInt("id"); emp.setId(id); String eName = resultSet.getString("ename"); emp.seteName(eName); int jobID = resultSet.getInt("job_id"); emp.setJob_id(jobID); int mgr = resultSet.getInt("mgr"); emp.setMgr(mgr); Date joinDate = resultSet.getDate("joindate"); emp.setDate(joinDate); Double salary = resultSet.getDouble("salary"); emp.setSalary(salary); Double bonus = resultSet.getDouble("bonus"); emp.setBonus(bonus); int deptID = resultSet.getInt("dept_id"); emp.setDept_id(deptID); list.add(emp);//将表中每一行信息添加到集合中 } } catch (SQLException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } finally { if(resultSet != null) { try { resultSet.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(stmt != null) { try { stmt.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(conn != null) { try { conn.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } } return list; } }
JDBC工具类
-
可以设计一个工具类JdbcUtilities,其中有以下方法
-
注册驱动
-
获取连接对象
可以使用配置文件,读取参数,为
getConnection(String url, String username, String password)
方法传参 -
释放资源
-
-
示例Code
public class JdbcUtilities { private static String url = null; private static String username = null; private static String password = null; private static String driver =null; static { try { ClassLoader classLoader = JdbcUtilities.class.getClassLoader(); //InputStream is = classLoader.getResourceAsStream("JDBC.properties"); URL resource = classLoader.getResource("JDBC.properties"); String path = resource.getPath(); Properties properties = new Properties(); //properties.load(is); properties.load(new FileReader(path)); url = properties.getProperty("url"); username = properties.getProperty("username"); password = properties.getProperty("password"); driver = properties.getProperty("driver"); Class.forName(driver); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConn() throws SQLException, IOException { Connection conn = DriverManager.getConnection(url, username, password); return conn; } public static void close(ResultSet rs, Statement stmt, Connection conn){ if(rs != null) { try { rs.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(stmt != null) { try { stmt.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(conn != null) { try { conn.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } } }
//使用JDBC工具类重做之前的JDBC实例 public class JdbcDemo09 { public static void main(String[] args) { JdbcDemo08 jdbcDemo08 = new JdbcDemo08(); List<Emp> allInfo = jdbcDemo08.getAllInfo(); //System.out.println(allInfo); for(Emp ele : allInfo) { System.out.println(ele); } } public List<Emp> getAllInfo() { List<Emp> list = new ArrayList<>(); Connection conn = null; Statement stmt = null; ResultSet resultSet = null; try { //Class.forName("com.mysql.jdbc.Driver"); //conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db2","root", "root"); conn = JdbcUtilities.getConn(); stmt = conn.createStatement(); String sql = "SELECT * FROM emp"; resultSet = stmt.executeQuery(sql); Emp emp = null; while(resultSet.next()) { int id = resultSet.getInt("id"); String eName = resultSet.getString("ename"); int jobID = resultSet.getInt("job_id"); int mgr = resultSet.getInt("mgr"); Date joinDate = resultSet.getDate("joindate"); Double salary = resultSet.getDouble("salary"); Double bonus = resultSet.getDouble("bonus"); int deptID = resultSet.getInt("dept_id"); emp = new Emp(); emp.setId(id); emp.seteName(eName); emp.setJob_id(jobID); emp.setMgr(mgr); emp.setDate(joinDate); emp.setSalary(salary); emp.setBonus(bonus); emp.setDept_id(deptID); list.add(emp); } } catch (SQLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { JdbcUtilities.close(resultSet, stmt, conn); } return list; } }
JDBC登录案例
-
实现需求:
- 通过键盘输入用户名和密码
- 判断用户是否登录成功
-
示例Code
#该案例使用的表 CREATE TABLE user( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(32), password VARCHAR(32) ); INSERT INTO user VALUES (null, "33", "a3b3"); INSERT INTO user VALUES (null, "34", "qwer");
public class JdbcDemo10 { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); String str1 = scanner.next(); String str2 = scanner.next(); boolean returnValue = new JdbcDemo10().userLogin(str1, str2); if(returnValue) { System.out.println("successfully login"); } else { System.out.println("fail to login"); } } public boolean userLogin(String name, String password) { if(name == null || password == null) { return false; } Connection conn = null; Statement statement = null; ResultSet resultSet = null; try { conn = JdbcUtilities.getConn(); statement = conn.createStatement(); //字符串拼接,使用传入的参数name和password String sql = "select * from user where username = '"+name+"' and password = '"+password+"' "; resultSet = statement.executeQuery(sql); //next方法返回值为boolean,若有sql中查询的一行则返回true,否则返回false return resultSet.next(); } catch (SQLException throwables) { throwables.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { JdbcUtilities.close(resultSet, statement, conn); } return false; } } //存在sql注入问题 /*input: dhuf dbv' or 'ac' = 'ac */ /*output: select * from user where username = 'dhuf' and password = 'dbv' or 'ac' = 'ac' successfully login */
PreparedStatement类
-
PreparedStatement类是Statement类的子类
-
作用:作用同Statement类都是执行sql的对象,但同时解决了sql注入问题
-
sql注入问题:在拼接sql时,有一些sql的特殊关键字参与字符串的拼接,会造成安全问题
在以上的例程中都使用了Statement类方法来执行sql的对象,但是输入特殊字符拼接,可以导致强行登录的问题
//JDBC登录案例,控制台打印信息 ahsdjh//输入任意用户名 abcd' or 'ghgh' = 'ghgh//输入密码 select * from user where username = 'ahsdjh' and password = 'abcd' or 'ghgh' = 'ghgh' //or右边的比较是恒成立的,or优先级高于and,所以where后面表达式为true,相当于where失效 successfully login//成功登录
-
使用PreparedStatement对象解决sql注入的问题
-
使用预编译的sql,格式:参数使用
?
作为占位符 -
使用步骤:
-
导入驱动jar包mysql-connector-java-5.1.37-bin.jar
-
注册驱动
-
获取数据库连接对象Connection
-
定义sql
注意:sql的参数使用
?
作为占位符select * from user where username = ? and password = ?;
-
获取执行sql语句的对象PreparedStatement
Connection类对象.preparedStatement(String sql)
-
给
?
赋值使用PreparedStatement类的方法:
setXxx(参数1,参数2)
参数1:
?
的位置索引从1开始参数2:
?
的值 -
执行sql,接收返回结果
PreparedStatement类中execute之类的方法无参数
PreparedStatement中继承自Statement中的方法有参数,但此时不用这些方法,用子类中的无参数方法
-
处理结果
-
释放资源
-
-
注意:
后期都会使用PreparedStatement来完成增删改查的所有操作
- 可以防止sql注入
- 效率更高
-
-
示例Code
public class JdbcDemo11 { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); String str1 = scanner.nextLine(); String str2 = scanner.nextLine(); boolean returnValue = new JdbcDemo11().userLogin(str1, str2); if(returnValue) { System.out.println("successfully login"); } else { System.out.println("fail to login"); } } public boolean userLogin(String name, String password) { if(name == null || password == null) { return false; } Connection conn = null; PreparedStatement pStmt = null; ResultSet resultSet = null; try { conn = JdbcUtilities.getConn(); String sql = "select * from user where username = ? and password = ? "; pStmt = conn.prepareStatement(sql); //System.out.println(sql); pStmt.setString(1, name); pStmt.setString(2, password); resultSet = pStmt.executeQuery(); return resultSet.next(); } catch (SQLException throwables) { throwables.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { JdbcUtilities.close(resultSet, pStmt, conn);//这里pStmt传参,父类引用指向子类对象,多态 } return false; } } /*input: dhfjd ap' or 'aaa' = 'aaa */ /*output: select * from user where username = ? and password = ? fail to login */
JDBC管理事务
-
事务:一个包含多个步骤的业务操作,如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败
-
管理事务的操作:
- 开启事务
- 提交事务
- 回滚事务
-
使用Connection类中的方法来管理事务
-
开启事务:在代码中,执行sql之前开启事务
setAutoCommit(boolean autocommit)
调用该方法设置参数为false,就是开启事务
-
提交事务:在代码中,当所有sql都执行完提交事务
commit()
-
回滚事务:在代码中,在异常处理的catch中回滚事务
rollback()
-
-
示例Code
public class JdbcDemo12 { public static void main(String[] args) { new JdbcDemo12().transfer(); } public void transfer() { Connection conn = null; PreparedStatement pStmt1 = null; PreparedStatement pStmt2 = null; try { conn = JdbcUtilities.getConn(); conn.setAutoCommit(false); String sql1 = "UPDATE account SET balance = balance - ? WHERE id = ?"; String sql2 = "UPDATE account SET balance = balance + ? WHERE id = ?"; pStmt1 = conn.prepareStatement(sql1); pStmt2 = conn.prepareStatement(sql2); pStmt1.setDouble(1, 500); pStmt2.setDouble(1, 500); pStmt1.setInt(2, 1); pStmt2.setInt(2, 2); pStmt1.executeUpdate(); /*在两次转账操作间设置异常操作 String str = null; str.toLowerCase();*/ pStmt2.executeUpdate(); conn.commit(); /* } catch (SQLException throwables) { throwables.printStackTrace(); } catch (IOException e) { e.printStackTrace(); */ }catch (Exception e) { try { //catch中设置回滚事务 if(conn != null) { conn.rollback(); } } catch (SQLException throwables) { throwables.printStackTrace(); } e.printStackTrace(); } finally { JdbcUtilities.close(pStmt1, conn); JdbcUtilities.close(pStmt2, null); } } }
二、数据库连接池
数据库连接池概述
-
数据库连接池就是一个容器(集合),存放数据库连接的容器。
当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完之后,会将连接对象归还给容器
-
数据库连接池的好处
- 节约资源
- 用户访问高效
-
数据库连接池的实现
-
标准接口
DataSource
,在javax.sql包下的-
方法:
获取连接:
getConnection()
归还连接:如果连接对象Connection是从连接池中获取的,那么调用
Connection.Close()
方法,则不会再关闭连接了,而是归还连接
-
-
一般普通开发者不去实现它,由数据库厂商实现
- c3p0:数据库连接池技术
- Druid:数据库连接池实现技术,由阿里巴巴提供
-
数据库连接池c3p0
-
使用步骤
-
导入jar包
c3p0-0.9.5.2.jar
和依赖jar包mchange-commons-java-0.2.12.jar
同时需要有导入的数据库驱动jar包
mysql-connector-java-5.1.37-bin.jar
-
定义配置文件:
配置文件名称:
c3p0.properties
或者c3p0-config.xml
路径:直接将文件放在src目录下即可
-
创建核心对象,即数据库连接池对象
ComboPooledDataSource
该构造方法中无参是读取默认配置,若有String参数是传入指定配置的配置名称来使用指定配置
-
获取连接:
getConnection
-
-
示例Code
//示例1:使用连接池 public class Demo01c3p0 { public static void main(String[] args) throws SQLException { //创建数据库连接池对象 DataSource ds = new ComboPooledDataSource(); //获取连接对象 Connection connection = ds.getConnection(); System.out.println(connection); } } /*output:打印日志信息 和 connection对象的信息 Jul 08, 2021 10:57:59 PM com.mchange.v2.log.MLog INFO: MLog clients using java 1.4+ standard logging. Jul 08, 2021 10:58:00 PM com.mchange.v2.c3p0.C3P0Registry INFO: Initializing c3p0-0.9.5.2 [built 08-December-2015 22:06:04 -0800; debug? true; trace: 10] Jul 08, 2021 10:58:00 PM com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource INFO: Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 3000, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, contextClassLoaderSource -> caller, dataSourceName -> 1b60699ai11cqj5idnrclk|525b461a, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, extensions -> {}, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, forceSynchronousCheckins -> false, forceUseNamedDriverClass -> false, identityToken -> 1b60699ai11cqj5idnrclk|525b461a, idleConnectionTestPeriod -> 0, initialPoolSize -> 5, jdbcUrl -> jdbc:mysql://localhost:3306/db3, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 10, maxStatements -> 0, maxStatementsPerConnection -> 0, minPoolSize -> 3, numHelperThreads -> 3, preferredTestQuery -> null, privilegeSpawnedThreads -> false, properties -> {password=******, user=******}, propertyCycle -> 0, statementCacheNumDeferredCloseThreads -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, userOverrides -> {}, usesTraditionalReflectiveProxies -> false ] com.mchange.v2.c3p0.impl.NewProxyConnection@11bd0f3b [wrapping: com.mysql.jdbc.JDBC4Connection@c333c60] */
//示例2:根据XML配置文件中的信息测试最大连接 public class Demo02c3p0 { public static void main(String[] args) throws SQLException { // DataSource ds = new ComboPooledDataSource(); // for(int i = 0; i < 10; i++) { // Connection connection = ds.getConnection(); // System.out.println(i + ":" + connection); // } testMaxPoolSize1(); //testMaxPoolSize2(); } public static void testMaxPoolSize1() throws SQLException { //这里使用无参数构造创建对象,使用默认配置的配置信息,XML中最大连接数为10 DataSource ds = new ComboPooledDataSource(); for(int i = 0; i < 11; i++) { Connection connection = ds.getConnection(); System.out.println(i + ":" + connection); //这里第6次连接后关闭,这样可以总共连接11个 if(i == 5) { connection.close(); } } } public static void testMaxPoolSize2() throws SQLException { //使用指定的配置"otherc3p0"中的配置信息,XML中最大连接数为8 DataSource ds = new ComboPooledDataSource("otherc3p0"); for(int i = 0; i < 9; i++) { Connection connection = ds.getConnection(); System.out.println(i + ":" + connection); //这里第6次连接后关闭,这样可以总共连接9个 if(i == 5) { connection.close(); } } } }
<c3p0-config> <!-- 使用默认的配置读取连接池对象 --> <default-config> <!-- 连接参数 --> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost:3306/db3</property> <property name="user">root</property> <property name="password">root</property> <!-- 连接池参数 --> <property name="initialPoolSize">5</property> <property name="maxPoolSize">10</property> <property name="checkoutTimeout">3000</property> </default-config> <named-config name="otherc3p0"> <!-- 连接参数 --> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost:3306/db3</property> <property name="user">root</property> <property name="password">root</property> <!-- 连接池参数 --> <property name="initialPoolSize">5</property> <property name="maxPoolSize">8</property> <property name="checkoutTimeout">1000</property> </named-config> </c3p0-config>
数据库连接池Druid
-
使用步骤
-
导入jar包
druid-1.0.9.jar
-
定义配置文件:
druid.properties
是properties格式的,可以放在任意目录下
-
加载配置文件
通过
Properties
中的load
方法 -
获取数据库连接池对象:
通过工厂类
DruidDataSourceFactory
中的静态方法createDataSource
-
获取连接:
通过
DataSource
类中的getConnection
方法
-
-
示例Code
public class Demo03Druid { public static void main(String[] args) throws Exception { //加载配置文件 InputStream is = Demo03Druid.class.getClassLoader().getResourceAsStream("druid.properties"); Properties prop = new Properties(); prop.load(is); //获取连接池对象 DataSource dataSource = DruidDataSourceFactory.createDataSource(prop); //获取连接 Connection connection = dataSource.getConnection(); //打印连接对象 System.out.println(connection); } } /*output: Jul 09, 2021 3:35:42 PM com.alibaba.druid.pool.DruidDataSource info INFO: {dataSource-1} inited com.mysql.jdbc.JDBC4Connection@6c40365c */
Druid工具类
-
定义工具类的实现步骤:
- 定义一个类
JDBCUtils
- 提供静态代码块加载配置文件,初始化连接池对象
- 提供方法
- 获取连接的方法:通过数据库连接池获取
- 释放资源
- 获取连接池的方法
- 定义一个类
-
示例Code
public class JDBCUtils { //定义成员变量DataSource private static DataSource ds; static { try { //加载配置文件 Properties prop = new Properties(); prop.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties")); //获取DataSource ds = DruidDataSourceFactory.createDataSource(prop); } catch (Exception e) { e.printStackTrace(); } } //获取连接池对象ds public static DataSource getDataSource() { return ds; } //获取连接 public static Connection getConnection() throws SQLException { return ds.getConnection(); } //释放资源,使用executeQuery会返回ResultSet对象 public static void close(Connection conn, Statement stmt, ResultSet rs) { if(rs != null) { try { rs.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(stmt != null) { try { stmt.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(conn != null) { try { conn.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } } //释放资源,使用executeUpdate //这里方法体直接调用了上面定义的3个参数的方法重载形式 public static void close(Connection conn, Statement stmt) { close(conn, stmt, null); } }
-
测试Druid工具类
//为数据库db3中的表account添加一条数据 public class Demo04TestDruid { public static void main(String[] args) { Connection connection = null; PreparedStatement pstmt = null; try { connection = JDBCUtils.getConnection(); String sql = "INSERT INTO account VALUES (null, ?, ?)"; pstmt = connection.prepareStatement(sql); pstmt.setString(1, "Lucy"); pstmt.setDouble(2, 3500); int count = pstmt.executeUpdate(); System.out.println(count); } catch (SQLException throwables) { throwables.printStackTrace(); } finally { JDBCUtils.close(connection, pstmt); } } } /*output:返回1表示表中有一条改动 Jul 09, 2021 4:57:44 PM com.alibaba.druid.pool.DruidDataSource info INFO: {dataSource-1} inited 1 */
三、Spring中的JdbcTemplate类
JdbcTemplate概述
-
Spring JDBC是Spring框架对JDBC的简单封装,其中提供了一个
JdbcTemplate
类简化JDBC的开发 -
使用步骤:
-
导入jar包
- commons-logging-1.2.jar
- spring-beans-5.0.0.RELEASE.jar
- spring-core-5.0.0.RELEASE.jar
- spring-jdbc-5.0.0.RELEASE.jar
- spring-tx-5.0.0.RELEASE.jar
同时需要有导入的数据库驱动jar包
mysql-connector-java-5.1.37-bin.jar
-
创建
JdbcTemplate
对象,这个对象依赖于数据库连接池(数据源)DataSource
JdbcTemplate template = new JdbcTemplate(ds);
-
调用
JdbcTemplate
的方法来完成CRUD的操作-
update()
:执行DML语句(增删改语句) -
queryForMap()
:将查询到的结果集封装为Map集合,其中列名为key,值作为value注意:这个方法查询的结果集长度只能是1, 例如
queryForMap(sql语句字符串, arg参数)
-
queryForList()
:将查询到的结果集封装为List集合注意:将每一条记录封装为一个Map集合,再将Map结合装载到List集合中
-
query()
:查询结果,将结果封装为JavaBean对象方法
query
的参数:RowMapper
接口类型的对象一般使用
BeanPropertyRowMapper
实现类,可以完成数据到JavaBean的自动封装格式:
new BeanPropertyRowMapper<类型>(类型.class)
-
queryForObject()
:查询结果,将结果封装为对象多用于使用了聚合函数的查询
-
-
-
示例Code
public class TestJdbcTemplate { public static void main(String[] args) throws Exception { //创建JdbcTemplate对象 DataSource dataSource = JDBCUtils.getDataSource(); JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); //调用JdbcTemplate对象中的方法 String sql = "UPDATE account SET balance = 100 WHERE id = ?"; //update方法中传入sql语句和sql语句中的参数 int update = jdbcTemplate.update(sql, 3); System.out.println(update); } } /*output:返回1表示表中有一条改动 Jul 09, 2021 5:36:58 PM com.alibaba.druid.pool.DruidDataSource info INFO: {dataSource-1} inited 1 */
JdbcTemplate执行DML语句
-
Jdbc Template执行DML语句的方法:
update()
:执行DML语句(增删改语句) -
示例Code
//使用Junit单元测试,单独测试JdbcTemplate类中的增、删、改方法 public class JdbcTemplateTest { private JdbcTemplate jdbcTemplate = new JdbcTemplate(JDBCUtils.getDataSource()); //更改一条数据 @Test public void testUpdate1() { String sql = "UPDATE emp SET salary = 10000 WHERE id = 1001"; int count = jdbcTemplate.update(sql); System.out.println(count); } /*output: Jul 09, 2021 9:50:29 PM com.alibaba.druid.pool.DruidDataSource info INFO: {dataSource-1} inited 1 */ //插入一条数据 @Test public void testUpdate2() { String sql = "INSERT INTO emp (id, ename, dept_id) VALUES(?, ?, ?)"; int count = jdbcTemplate.update(sql, 1016, "Jake", 10); System.out.println(count); } /*output: Jul 09, 2021 9:51:40 PM com.alibaba.druid.pool.DruidDataSource info INFO: {dataSource-1} inited 1 */ //删除一条数据 @Test public void testUpdate3() { String sql = "DELETE FROM emp WHERE ename = ?"; int count = jdbcTemplate.update(sql, "Jake"); System.out.println(count); } /*output: Jul 09, 2021 9:52:39 PM com.alibaba.druid.pool.DruidDataSource info INFO: {dataSource-1} inited 1 */ }
JdbcTemplate执行DQL语句
-
Jdbc Template执行DQL语句的方法:
-
queryForMap()
:将查询到的结果集封装为Map集合,其中列名为key,值作为value注意:这个方法查询的结果集长度只能是1, 例如
queryForMap(sql语句字符串, arg参数)
-
queryForList()
:将查询到的结果集封装为List集合注意:将每一条记录封装为一个Map集合,再将Map结合装载到List集合中
-
query()
:查询结果,将结果封装为JavaBean对象,此方法需要使用一个预定义的类(成员变量为表中的字段,类中包含getter和setter方法、toString方法的重写)方法
query
的参数:需要传入RowMapper
接口类型的对象,可以自定义实现类(或者用匿名内部类),也可以使用一些给定的实现类一般使用
BeanPropertyRowMapper
实现类,可以完成数据到JavaBean的自动封装格式:
new BeanPropertyRowMapper<类型>(类型.class)
注意:预定义的类型中,类的成员变量必须是引用类型,若有基本数据类型要使用其对应的包装类
否则会出现org.springframework.beans.TypeMismatchException
-
queryForObject()
:查询结果,将结果封装为对象一般用于使用了聚合函数的查询
-
-
示例Code
//queryForMap():将查询到的结果集封装为Map集合,其中列名为key,值作为value //这个方法查询的结果集长度只能是1, 例如:queryForMap(sql语句字符串, arg参数),预编译sql参数只能有一个 public class TestJdbcTemplate2 { private JdbcTemplate jdbcTemplate = new JdbcTemplate(JDBCUtils.getDataSource()); @Test public void testQueryForMap() { String sql = "SELECT * FROM emp WHERE id = ?"; //这里只能是查询一个id中的记录 Map<String, Object> map = jdbcTemplate.queryForMap(sql, 1001); //打印map System.out.println(map); //遍历打印map中的key和value for(String ele : map.keySet()) { System.out.println(ele + ":" + map.get(ele)); } } } /*output:打印日志信息+测试类中测试方法执行输出结果 Jul 09, 2021 11:14:58 PM com.alibaba.druid.pool.DruidDataSource info INFO: {dataSource-1} inited {id=1001, ename=George, job_id=4, mgr=1004, joindate=2000-12-17, salary=10000.00, bonus=null, dept_id=10} =========== id:1001 ename:George job_id:4 mgr:1004 joindate:2000-12-17 salary:10000.00 bonus:null dept_id:10 */
//queryForList(String sql):将查询到的结果集封装为List集合 public class TestJdbcTemplate2 { @Test public void testQueryForList() { String sql = "SELECT * FROM emp"; List<Map<String, Object>> list = jdbcTemplate.queryForList(sql); //打印这个list System.out.println(list); System.out.println("============="); //遍历打印这个list中的元素 for(Map<String, Object> ele : list) { System.out.println(ele); } } } /*output:打印日志信息+测试类中测试方法执行输出结果 Jul 09, 2021 11:10:26 PM com.alibaba.druid.pool.DruidDataSource info INFO: {dataSource-1} inited [{id=1001, ename=George, job_id=4, mgr=1004, joindate=2000-12-17, salary=10000.00, bonus=null, dept_id=10}, {id=1002, ename=卢俊义, job_id=3, mgr=1006, joindate=2001-02-20, salary=16000.00, bonus=3000.00, dept_id=10}, {id=1003, ename=林冲, job_id=3, mgr=1006, joindate=2001-02-22, salary=12500.00, bonus=5000.00, dept_id=30}, {id=1004, ename=唐僧, job_id=2, mgr=1009, joindate=2001-04-02, salary=29750.00, bonus=null, dept_id=20}, {id=1005, ename=李逵, job_id=4, mgr=1006, joindate=2001-09-28, salary=12500.00, bonus=14000.00, dept_id=30}, {id=1006, ename=宋江, job_id=2, mgr=1009, joindate=2001-05-01, salary=28500.00, bonus=null, dept_id=30}, {id=1007, ename=刘备, job_id=2, mgr=1009, joindate=2001-09-01, salary=24500.00, bonus=null, dept_id=10}, {id=1008, ename=猪八戒, job_id=4, mgr=1004, joindate=2007-04-19, salary=30000.00, bonus=null, dept_id=20}, {id=1009, ename=罗贯中, job_id=1, mgr=null, joindate=2001-11-17, salary=50000.00, bonus=null, dept_id=10}, {id=1010, ename=吴用, job_id=3, mgr=1006, joindate=2001-09-08, salary=15000.00, bonus=0.00, dept_id=30}, {id=1011, ename=沙僧, job_id=4, mgr=1004, joindate=2007-05-23, salary=11000.00, bonus=null, dept_id=20}, {id=1012, ename=李逵, job_id=4, mgr=1006, joindate=2001-12-03, salary=9500.00, bonus=null, dept_id=30}, {id=1013, ename=小白龙, job_id=4, mgr=1004, joindate=2001-12-03, salary=30000.00, bonus=null, dept_id=20}, {id=1014, ename=关羽, job_id=4, mgr=1007, joindate=2002-01-23, salary=13000.00, bonus=null, dept_id=10}, {id=1015, ename=悟, job_id=null, mgr=1004, joindate=2000-12-17, salary=8000.00, bonus=null, dept_id=20}] ============= {id=1001, ename=George, job_id=4, mgr=1004, joindate=2000-12-17, salary=10000.00, bonus=null, dept_id=10} {id=1002, ename=卢俊义, job_id=3, mgr=1006, joindate=2001-02-20, salary=16000.00, bonus=3000.00, dept_id=10} {id=1003, ename=林冲, job_id=3, mgr=1006, joindate=2001-02-22, salary=12500.00, bonus=5000.00, dept_id=30} {id=1004, ename=唐僧, job_id=2, mgr=1009, joindate=2001-04-02, salary=29750.00, bonus=null, dept_id=20} {id=1005, ename=李逵, job_id=4, mgr=1006, joindate=2001-09-28, salary=12500.00, bonus=14000.00, dept_id=30} {id=1006, ename=宋江, job_id=2, mgr=1009, joindate=2001-05-01, salary=28500.00, bonus=null, dept_id=30} {id=1007, ename=刘备, job_id=2, mgr=1009, joindate=2001-09-01, salary=24500.00, bonus=null, dept_id=10} {id=1008, ename=猪八戒, job_id=4, mgr=1004, joindate=2007-04-19, salary=30000.00, bonus=null, dept_id=20} {id=1009, ename=罗贯中, job_id=1, mgr=null, joindate=2001-11-17, salary=50000.00, bonus=null, dept_id=10} {id=1010, ename=吴用, job_id=3, mgr=1006, joindate=2001-09-08, salary=15000.00, bonus=0.00, dept_id=30} {id=1011, ename=沙僧, job_id=4, mgr=1004, joindate=2007-05-23, salary=11000.00, bonus=null, dept_id=20} {id=1012, ename=李逵, job_id=4, mgr=1006, joindate=2001-12-03, salary=9500.00, bonus=null, dept_id=30} {id=1013, ename=小白龙, job_id=4, mgr=1004, joindate=2001-12-03, salary=30000.00, bonus=null, dept_id=20} {id=1014, ename=关羽, job_id=4, mgr=1007, joindate=2002-01-23, salary=13000.00, bonus=null, dept_id=10} {id=1015, ename=悟, job_id=null, mgr=1004, joindate=2000-12-17, salary=8000.00, bonus=null, dept_id=20} /
//query(String sql, RowMapper<T> rowMapper):查询结果,将结果封装为JavaBean对象 //这里使用的是给定的实现类BeanPropertyRowMapper public class TestJdbcTemplate2 { @Test public void testQuery() { String sql = "SELECT * FROM emp"; List<Emp> query = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Emp>(Emp.class)); System.out.println(query); } } /*output:打印日志信息+测试类中测试方法执行输出结果 Jul 09, 2021 11:44:01 PM com.alibaba.druid.pool.DruidDataSource info INFO: {dataSource-1} inited [Emp{id=1001, eName='George', job_id=4, mgr=1004, date=null, salary=10000.0, bonus=null, dept_id=10}, Emp{id=1002, eName='卢俊义', job_id=3, mgr=1006, date=null, salary=16000.0, bonus=3000.0, dept_id=10}, Emp{id=1003, eName='林冲', job_id=3, mgr=1006, date=null, salary=12500.0, bonus=5000.0, dept_id=30}, Emp{id=1004, eName='唐僧', job_id=2, mgr=1009, date=null, salary=29750.0, bonus=null, dept_id=20}, Emp{id=1005, eName='李逵', job_id=4, mgr=1006, date=null, salary=12500.0, bonus=14000.0, dept_id=30}, Emp{id=1006, eName='宋江', job_id=2, mgr=1009, date=null, salary=28500.0, bonus=null, dept_id=30}, Emp{id=1007, eName='刘备', job_id=2, mgr=1009, date=null, salary=24500.0, bonus=null, dept_id=10}, Emp{id=1008, eName='猪八戒', job_id=4, mgr=1004, date=null, salary=30000.0, bonus=null, dept_id=20}, Emp{id=1009, eName='罗贯中', job_id=1, mgr=null, date=null, salary=50000.0, bonus=null, dept_id=10}, Emp{id=1010, eName='吴用', job_id=3, mgr=1006, date=null, salary=15000.0, bonus=0.0, dept_id=30}, Emp{id=1011, eName='沙僧', job_id=4, mgr=1004, date=null, salary=11000.0, bonus=null, dept_id=20}, Emp{id=1012, eName='李逵', job_id=4, mgr=1006, date=null, salary=9500.0, bonus=null, dept_id=30}, Emp{id=1013, eName='小白龙', job_id=4, mgr=1004, date=null, salary=30000.0, bonus=null, dept_id=20}, Emp{id=1014, eName='关羽', job_id=4, mgr=1007, date=null, salary=13000.0, bonus=null, dept_id=10}, Emp{id=1015, eName='悟', job_id=null, mgr=1004, date=null, salary=8000.0, bonus=null, dept_id=20}] */
//query(String sql, RowMapper<T> rowMapper):查询结果,将结果封装为JavaBean对象 //使用匿名内部类实现RowMapper接口,需要重写mapRow方法,效果同上个例程 //这种写法类似于之前的“JDBC实例”和“JDBC工具类”中的写法 public class TestJdbcTemplate2 { @Test public void testQuery2() { String sql = "SELECT * FROM emp"; List<Emp> query = jdbcTemplate.query(sql, new RowMapper<Emp>() { @Override public Emp mapRow(ResultSet resultSet, int i) throws SQLException { Emp emp = new Emp(); int id = resultSet.getInt("id"); String eName = resultSet.getString("ename"); int job_id = resultSet.getInt("job_id"); int mgr = resultSet.getInt("mgr"); Date date = resultSet.getDate("joindate"); Double salary = resultSet.getDouble("salary"); Double bonus = resultSet.getDouble("bonus"); int dept_id = resultSet.getInt("dept_id"); emp.setId(id); emp.seteName(eName); emp.setJob_id(job_id); emp.setMgr(mgr); emp.setDate(date); emp.setSalary(salary); emp.setBonus(bonus); emp.setDept_id(dept_id); return emp; } }); System.out.println(query); } } /*output:打印日志信息+测试类中测试方法执行输出结果 Jul 10, 2021 12:14:08 AM com.alibaba.druid.pool.DruidDataSource info INFO: {dataSource-1} inited [Emp{id=1001, eName='George', job_id=4, mgr=1004, date=2000-12-17, salary=10000.0, bonus=0.0, dept_id=10}, Emp{id=1002, eName='卢俊义', job_id=3, mgr=1006, date=2001-02-20, salary=16000.0, bonus=3000.0, dept_id=10}, Emp{id=1003, eName='林冲', job_id=3, mgr=1006, date=2001-02-22, salary=12500.0, bonus=5000.0, dept_id=30}, Emp{id=1004, eName='唐僧', job_id=2, mgr=1009, date=2001-04-02, salary=29750.0, bonus=0.0, dept_id=20}, Emp{id=1005, eName='李逵', job_id=4, mgr=1006, date=2001-09-28, salary=12500.0, bonus=14000.0, dept_id=30}, Emp{id=1006, eName='宋江', job_id=2, mgr=1009, date=2001-05-01, salary=28500.0, bonus=0.0, dept_id=30}, Emp{id=1007, eName='刘备', job_id=2, mgr=1009, date=2001-09-01, salary=24500.0, bonus=0.0, dept_id=10}, Emp{id=1008, eName='猪八戒', job_id=4, mgr=1004, date=2007-04-19, salary=30000.0, bonus=0.0, dept_id=20}, Emp{id=1009, eName='罗贯中', job_id=1, mgr=0, date=2001-11-17, salary=50000.0, bonus=0.0, dept_id=10}, Emp{id=1010, eName='吴用', job_id=3, mgr=1006, date=2001-09-08, salary=15000.0, bonus=0.0, dept_id=30}, Emp{id=1011, eName='沙僧', job_id=4, mgr=1004, date=2007-05-23, salary=11000.0, bonus=0.0, dept_id=20}, Emp{id=1012, eName='李逵', job_id=4, mgr=1006, date=2001-12-03, salary=9500.0, bonus=0.0, dept_id=30}, Emp{id=1013, eName='小白龙', job_id=4, mgr=1004, date=2001-12-03, salary=30000.0, bonus=0.0, dept_id=20}, Emp{id=1014, eName='关羽', job_id=4, mgr=1007, date=2002-01-23, salary=13000.0, bonus=0.0, dept_id=10}, Emp{id=1015, eName='悟', job_id=0, mgr=1004, date=2000-12-17, salary=8000.0, bonus=0.0, dept_id=20}] */
//queryForObject(String sql, Class<T> requiredType):查询结果,将结果封装为对象 public class TestJdbcTemplate2 { @Test public void testQueryForObject() { String sql = "SELECT COUNT(id) FROM emp"; Integer count = jdbcTemplate.queryForObject(sql, Integer.class); System.out.println(count); } } /*output:打印日志信息+测试类中测试方法执行输出结果 Jul 09, 2021 11:34:00 PM com.alibaba.druid.pool.DruidDataSource info INFO: {dataSource-1} inited 15 */
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具