Spring(5)——Spring 和数据库编程
本文内容纲要:
-传统JDBC回顾
-优化传统的JDBC
-Spring中的JDBC
传统JDBC回顾
JDBC我们一定不陌生,刚开始学习的时候,我们写过很多很多重复的模板代码:
publicStudentgetOne(intid){
Stringsql="SELECTid,nameFROMstudentWHEREid=?";
Studentstudent=null;
//声明JDBC变量
Connectioncon=null;
PreparedStatementps=null;
ResultSetrs=null;
try{
//注册驱动程序
Class.forName("com.myql.jdbc.Driver");
//获取连接
con=DriverManager.getConnection("jdbc://mysql://localhost:"+
"3306/student","root","root");
//预编译SQL
ps=con.prepareStatement(sql);
//设置参数
ps.setInt(1,id);
//执行SQL
rs=ps.executeQuery();
//组装结果集返回POJO
if(rs.next()){
student=newStudent();
student.setId(rs.getInt(1));
student.setName(rs.getString(1));
}
}catch(ClassNotFoundException|SQLExceptione){
e.printStackTrace();
}finally{
//关闭数据库连接资源
try{
if(rs!=null&&!rs.isClosed()){
rs.close();
}
}catch(SQLExceptione){
e.printStackTrace();
}
try{
if(ps!=null&&!ps.isClosed()){
ps.close();
}
}catch(SQLExceptione){
e.printStackTrace();
}
try{
if(con!=null&&con.isClosed()){
con.close();
}
}catch(SQLExceptione){
e.printStackTrace();
}
}
returnstudent;
}
现在光是看着就头大,并且我还把它完整的写了出来..真恶心!
这还仅仅是一个JDBC的方法,并且最主要的代码只有ps=con.prepareStatement(sql);
这么一句,而且有很多模板化的代码,包括建立连接以及关闭连接..我们必须想办法解决一下!
优化传统的JDBC
第一步:创建DBUtil类
我想第一步我们可以把重复的模板代码提出来创建一个【DBUtil】数据库工具类:
packageutil;
importjava.sql.Connection;
importjava.sql.DriverManager;
importjava.sql.SQLException;
publicclassDBUtil{
staticStringip="127.0.0.1";
staticintport=3306;
staticStringdatabase="student";
staticStringencoding="UTF-8";
staticStringloginName="root";
staticStringpassword="root";
static{
try{
Class.forName("com.mysql.jdbc.Driver");
}catch(ClassNotFoundExceptione){
e.printStackTrace();
}
}
publicstaticConnectiongetConnection()throwsSQLException{
Stringurl=String.format("jdbc:mysql://%s:%d/%s?characterEncoding=%s",ip,port,database,encoding);
returnDriverManager.getConnection(url,loginName,password);
}
}
这样我们就可以把上面的恶心的代码变成这样:
publicStudentgetOne(intid){
Stringsql="SELECTid,nameFROMstudentWHEREid=?";
Studentstudent=null;
//声明JDBC变量
Connectioncon=null;
PreparedStatementps=null;
ResultSetrs=null;
try{
//获取连接
con=DBUtil.getConnection();
//预编译SQL
ps=con.prepareStatement(sql);
//设置参数
ps.setInt(1,id);
//执行SQL
rs=ps.executeQuery();
//组装结果集返回POJO
....
}catch(SQLExceptione){
e.printStackTrace();
}finally{
//关闭数据库连接资源
....
}
returnstudent;
}
也只是少写了一句注册驱动程序少处理了一个异常而已,并没有什么大的变化,必须再优化一下
第二步:使用try-catch语句自动关闭资源
自动资源关闭是JDK7中新引入的特性,不了解的同学可以去看一下我之前写的文章:JDK7新特性
于是代码可以进一步优化成这样:
publicStudentgetOne(intid){
Stringsql="SELECTid,nameFROMstudentWHEREid=?";
Studentstudent=null;
//将JDBC声明变量包含在try(..)里将自动关闭资源
try(Connectioncon=DBUtil.getConnection();PreparedStatementps=con.prepareStatement(sql)){
//设置参数
ps.setInt(1,id);
//执行SQL
ResultSetrs=ps.executeQuery();
//组装结果集返回POJO
if(rs.next()){
student=newStudent();
student.setId(rs.getInt(1));
student.setName(rs.getString(1));
}
}catch(SQLExceptione){
e.printStackTrace();
}
returnstudent;
}
这样看着好太多了,但仍然不太满意,因为我们最核心的代码也就只是执行SQL语句并拿到返回集,再来再来
再进一步改进DBUtil类:
在DBUtil类中新增一个方法,用来直接返回结果集:
publicstaticResultSetgetResultSet(Stringsql,Object[]objects)throwsSQLException{
ResultSetrs=null;
try(Connectioncon=getConnection();PreparedStatementps=con.prepareStatement(sql)){
//根据传递进来的参数,设置SQL占位符的值
for(inti=0;i<objects.length;i++){
ps.setObject(i+1,objects[i]);
}
//执行SQL语句并接受结果集
rs=ps.executeQuery();
}
//返回结果集
returnrs;
}
这样我们就可以把我们最开始的代码优化成这样了:
publicStudentgetOne(intid){
Stringsql="SELECTid,nameFROMstudentWHEREid=?";
Object[]objects={id};
Studentstudent=null;
try(ResultSetrs=DBUtil.getResultSet(sql,objects);){
student.setId(rs.getInt(1));
student.setName(rs.getString(1));
}catch(SQLExceptione){
//处理异常
e.printStackTrace();
}
returnstudent;
}
wooh!看着爽多了,但美中不足的就是没有把try-catch语句去掉,我们也可以不进行异常处理直接把SQLException抛出去:
publicStudentgetOne(intid)throwsSQLException{
Stringsql="SELECTid,nameFROMstudentWHEREid=?";
Object[]objects={id};
Studentstudent=null;
try(ResultSetrs=DBUtil.getResultSet(sql,objects);){
student.setId(rs.getInt(1));
student.setName(rs.getString(1));
}
returnstudent;
}
其实上面的版本已经够好了,这样做只是有些强迫症。
- 我们自己定义的DBUtil工具已经很实用了,因为是从模板化的代码中抽离出来的,所以我们可以一直使用
Spring中的JDBC
要想使用Spring中的JDBC模块,就必须引入相应的jar文件:
- 需要引入的jar包:
- spring-jdbc-4.3.16.RELEASE.jar
- spring-tx-4.3.16.RELEASE.jar
好在IDEA在创建Spring项目的时候已经为我们自动部署好了,接下来我们来实际在Spring中使用一下JDBC:
配置数据库资源
就像我们创建DBUtil类,将其中连接的信息封装在里面一样,我们需要将这些数据库资源配置起来
- 配置方式:
- 使用简单数据库配置
- 使用第三方数据库连接池
我们可以使用Spring内置的类来配置,但大部分时候我们都会使用第三方数据库连接池来进行配置,由于使用第三方的类,一般采用XML文件配置的方式,我们这里也使用XML文件配置的形式:
使用简单数据库配置
首先我们来试试Spring的内置类org.springframework.jdbc.datasource.SimpleDriverDataSource
:
<beanid="dateSource"class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
<propertyname="username"value="root"/>
<propertyname="password"value="root"/>
<propertyname="driverClass"value="com.mysql.jdbc.Driver"/>
<propertyname="url"value="jdbc://mysql://locolhost:3306/student"/>
</bean>
我们来测试一下,先把我们的JDBC操作类写成这个样子:
packagejdbc;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.stereotype.Component;
importpojo.Student;
importjavax.sql.DataSource;
importjava.sql.*;
@Component("jdbc")
publicclassJDBCtest{
@Autowired
privateDataSourcedataSource;
publicStudentgetOne(intstuID)throwsSQLException{
Stringsql="SELECTid,nameFROMstudentWHEREid="+stuID;
Studentstudent=newStudent();
Connectioncon=dataSource.getConnection();
Statementst=con.createStatement();
ResultSetrs=st.executeQuery(sql);
if(rs.next()){
student.setId(rs.getInt("id"));
student.setName(rs.getString("name"));
}
returnstudent;
}
}
然后编写测试类:
ApplicationContextcontext=
newClassPathXmlApplicationContext("applicationContext.xml");
JDBCtestjdbc=(JDBCtest)context.getBean("jdbc");
Studentstudent=jdbc.getOne(123456789);
System.out.println(student.getId());
System.out.println(student.getName());
成功取出数据库中的数据:
使用第三方数据库连接池
上面配置的这个简单的数据源一般用于测试,因为它不是一个数据库连接池,知识一个很简单的数据库连接的应用。在更多的时候,我们需要使用第三方的数据库连接,比如使用C3P0数据库连接池:
<beanid="dataSource"class="com.mchange.v2.c3p0.ComboPooledDataSource">
<propertyname="driverClass"value="com.mysql.jdbc.Driver"></property>
<propertyname="jdbcUrl"value="jdbc:mysql:///hib_demo"></property>
<propertyname="user"value="root"></property>
<propertyname="password"value="root"></property>
<propertyname="initialPoolSize"value="3"></property>
<propertyname="maxPoolSize"value="10"></property>
<propertyname="maxStatements"value="100"></property>
<propertyname="acquireIncrement"value="2"></property>
</bean>
跟上面的测试差不多,不同的是需要引入相关支持C3P0数据库连接池的jar包而已。
JdbcTemplate
Spring中提供了一个JdbcTemplate类,它自己已经封装了一个DataSource类型的变量,我们可以直接使用:
<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd">
<beanid="dataSrouce"class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
<propertyname="username"value="root"/>
<propertyname="password"value="root"/>
<propertyname="driverClass"value="com.mysql.jdbc.Driver"/>
<propertyname="url"value="jdbc:mysql://localhost:3306/student"/>
</bean>
<context:component-scanbase-package="jdbc"/>
<beanid="jdbcTemplate"class="org.springframework.jdbc.core.JdbcTemplate">
<propertyname="dataSource"ref="dataSrouce"/>
</bean>
</beans>
我们来改写一下JDBC操作的类:
packagejdbc;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.jdbc.core.JdbcTemplate;
importorg.springframework.jdbc.core.RowMapper;
importorg.springframework.stereotype.Component;
importpojo.Student;
importjava.sql.*;
@Component("jdbc")
publicclassJDBCtest{
@Autowired
privateJdbcTemplatejdbcTemplate;
publicStudentgetOne(intstuID)throwsSQLException{
Stringsql="SELECTid,nameFROMstudentWHEREid=?";
Studentstudent=jdbcTemplate.queryForObject(sql,newRowMapper<Student>(){
@Override
publicStudentmapRow(ResultSetresultSet,inti)throwsSQLException{
Studentstu=newStudent();
stu.setId(resultSet.getInt("id"));
stu.setName(resultSet.getString("name"));
returnstu;
}
},123456789);
returnstudent;
}
}
测试类不变,运行可以获得正确的结果:
但是好像并没有简单多少的样子,那我们来看看其他CRUD的例子:
/**
*增加一条数据
*
*@paramstudent
*/
publicvoidadd(Studentstudent){
this.jdbcTemplate.update("INSERTINTOstudent(id,name)VALUES(?,?)",
student.getId(),student.getName());
}
/**
*更新一条数据
*
*@paramstudent
*/
publicvoidupdate(Studentstudent){
this.jdbcTemplate.update("UPDATEstudentSETname=?WHEREid=?",
student.getName(),student.getId());
}
/**
*删除一条数据
*
*@paramid
*/
publicvoiddelete(intid){
this.jdbcTemplate.update("DELETEFROMstudentWHEREid=?",
id);
}
现在应该简单多了吧,返回集合的话只需要稍微改写一下上面的getOne()方法就可以了
扩展阅读:官方文档、Spring中JdbcTemplate实现增删改查
参考资料:
- 《JavaEE互联网轻量级框架整合开发》
- 《Spring实战》
- 全能的百度和万能的大脑
扩展阅读:①彻底理解数据库事务、②Spring事务管理详解、③Spring事务管理(详解+实例)、④全面分析Spring的编程式事务管理及声明式事务管理
欢迎转载,转载请注明出处!
简书ID:@我没有三颗心脏
github:wmyskxz
欢迎关注公众微信号:wmyskxz_javaweb
分享自己的JavaWeb学习之路以及各种Java学习资料
本文内容总结:传统JDBC回顾,优化传统的JDBC,Spring中的JDBC,
原文链接:https://www.cnblogs.com/wmyskxz/p/8845799.html