首页 文章资讯内容详情

Spring(5)——Spring 和数据库编程

2026-06-01 2 花语

本文内容纲要:

-传统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