JDBC 简介
JDBC(Java Data Base Connectivity,Java 数据库连接)是一种用于执行 SQL 语句的JavaAPI,可以为多种关系数据库提供统一访问,它由一组用 Java 语言编写的类和接口组成。JDBC 为数据库开发人员提供了一个标准的 API,据此可以构建更高级的工具和接口,使数据库开发人员能够用纯 JavaAPI 编写数据库应用程序,并且可跨平台运行,且不收数据库供应商的限制。(在 JDBC 出来之前,是使用 ODBC-JDBC 桥去连接数据库,连接慢、资源浪费。)
JDBC 使用流程:
1.在开发环境中加载指定数据库的驱动程序
2.在 Java 程序中加载驱动程序
3.创造数据库连接对象
4.创建用于执行 SQL 并接收结果的 Statement 对象
5.通过 Statement 对象的特定方法执行 SQL,并得到结果
6.关闭数据库连接
JDBC的问题
1.数据库异常问题
2.每次调用数据库连接,都需要重复地打开数据库连接,过度的代码冗余
3.频繁的数据库连接,形成过度的资源浪费,影响程序性能
4.SQL 太死板,不易动态修改 SQL,也不利于系统的拓展性与维护性
5.结果的封装也比较死板
SpringJDBC 简介
Spring 中的 JDBC 连接与直接使用JDBC去连接有一定的差别,Spring 对 JDBC 做了大量封装,消除了冗余代码,使得开发量大大减小。
我们可能都处理过数据库访问功能,在实际的工作中也发现数据库访问有一些不足之处。我们必须初始化数据访问框架、打开连接、处理异常和关闭连接。如果上述操作出现任何问题,都有可能损坏或删除数据。
Spring 自带了一组数据访问框架,集成了多种数据访问技术,不管是直接通过 JDBC 还是像 Hibernate 这样的对象关系映射(Object-Relational-Mapping,ORM)框架实现数据库持久化,Spring 都能够帮你消除持久化代码中那些单调枯燥的数据访问逻辑。我们可以依赖 Spring 来处理底层的数据访问,以便于专注应用程序中数据的管理。
SpringJDBC 驱动配置:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/dbname?useSSL=true"></property>
<property name="username" value="username"></property>
<property name="password" value="password"></property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
JDBCTemplate用法:
execute:可用于执行任何 SQL 语句,一般用于执行 DDL 语句
update:用于执行新增、修改、删除等语句
query:用于执行查询语句
call:用于执行存储过程、函数相关语句
先呈现我 pom.xml 和 目录结构
数据库中的数据:
数据库表结构:
在 Spring-Jdbc 之前,增删改查的方式:
springConfig.xml 的内容:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd
">
<context:component-scan base-package="jdbc"/>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd
">
<context:component-scan base-package="jdbc"/>
</beans>
SpringVO 代码内容:
package jdbc;
public class SpringVO {
private long springId;
private String springName;
private String springVersion;
public long getSpringId() {
return springId;
}
public void setSpringId(long springId) {
this.springId = springId;
}
public String getSpringName() {
return springName;
}
public void setSpringName(String springName) {
this.springName = springName;
}
public String getSpringVersion() {
return springVersion;
}
public void setSpringVersion(String springVersion) {
this.springVersion = springVersion;
}
@Override
public String toString() {
return "SpringVO [springId=" + springId + ", springName=" + springName + ", springVersion=" + springVersion
+ "]";
}
public SpringVO(long springId, String springName, String springVersion) {
super();
this.springId = springId;
this.springName = springName;
this.springVersion = springVersion;
}
public SpringVO() {
super();
}
}
SpringDao 代码内容:
package jdbc;
import java.util.List;
public interface SpringDao {
int insertSpring();
List<SpringVO> listSpring();
}
SpringService 代码内容:(SpringService 此处只是打印出了查询后得到的数据)
package jdbc;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class SpringService {
@Autowired
private SpringDao springDao;
public void insertSpring() {
int ret = springDao.insertSpring();
System.out.println("batch " + ret + "datas");
}
public void listSpring() {
List<SpringVO> list = springDao.listSpring();
for (SpringVO springVo : list) {
System.out.println(springVo);
}
}
}
SpringDaoImpl 代码内容:
package jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Component;
@Component
public class SpringDaoImpl implements SpringDao {
public int insertSpring() {
Connection conn = null;
PreparedStatement stmt = null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/spring_jdbc?useSSL=true&serverTimezone=UTC",
"root", "root");
stmt = conn
.prepareStatement("insert into spring_text(spring_name,spring_version)values('SpringIOC','3.0')");
int row = stmt.executeUpdate();
System.out.println("execute row:" + row);
return row;
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return 0;
}
public List<SpringVO> listSpring() {
Connection conn = null;
PreparedStatement stmt = null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/spring_jdbc?useSSL=true&serverTimezone=UTC",
"root", "root");
stmt = conn.prepareStatement("select * from spring_text");
ResultSet rs = stmt.executeQuery();
List<SpringVO> list = new ArrayList<>();
while (rs.next()) {
list.add(new SpringVO(rs.getInt(1), rs.getString(2), rs.getString(3)));
}
return list;
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return null;
}
}
SpringTest 代码内容:
package jdbc;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringTest {
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("/jdbc/springConfig.xml");
SpringService springService = (SpringService) context.getBean("springService");
springService.listSpring();
}
}
执行结果:
SpringVO [springId=1, springName=SpringIOC, springVersion=3.0]
SpringVO [springId=2, springName=SpringAOP, springVersion=3.5]
SpringVO [springId=3, springName=SpringJDBC, springVersion=3.8]
SpringVO [springId=4, springName=SpringTX, springVersion=4.2]
会发现,单单只是查询和插入的操作,就会占用大量的代码,并且在处理查询和插入的时候,除了业务逻辑,还需要处理错误。这显然是不合理的,如果有大量的查询语句,就会造成代码的严重冗余。
现在使用 SpringJdbc 的方式来消除这些问题。
其中 SpringDao,SpringService,SpringVO,SpringTest中的代码并没有任何改变:
springConfig 代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd">
<context:component-scan base-package="springjdbc" />
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url"
value="jdbc:mysql://localhost:3306/spring_jdbc?useSSL=true&serverTimezone=UTC"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
SpringMapper 代码如下:(SpringMapper 实现了 RowMapper 接口)
package springjdbc;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.jdbc.core.RowMapper;
public class SpringMapper implements RowMapper<SpringVO> {
public SpringVO mapRow(ResultSet rs, int rowNum) throws SQLException {
SpringVO springVo = new SpringVO();
springVo.setSpringId(rs.getInt("spring_id"));
springVo.setSpringName(rs.getString("spring_name"));
springVo.setSpringVersion(rs.getString("spring_version"));
return springVo;
}
}
重点来了,SpringDaoImol 中的代码如下:
package springjdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.IntSummaryStatistics;
import java.util.List;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import springjdbc.impl.SpringDao;
@Component
public class SpringDaoImpl implements SpringDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public int insertSpring() {
String sql = "insert into spring_text(spring_name,spring_version)values(?,?)";
List<Object[]> batchArgs = new ArrayList<>();
batchArgs.add(new Object[] { "SpringAOP2", "4.4" });
batchArgs.add(new Object[] { "SpringAOP3", "4.4" });
int[] rows = jdbcTemplate.batchUpdate(sql, batchArgs);
List<Integer> primes = IntStream.of(rows).boxed().collect(Collectors.toList());
int sum = primes.stream().mapToInt(x -> x).sum();
// IntSummaryStatistics stats = primes.stream().mapToInt(x
// ->x).summaryStatistics();
// int sum = (int) stats.getSum();
// System.out.println(sum);
return sum;
}
public List<SpringVO> listSpring() {
String sql = "select * from spring_text";
List<SpringVO> list = jdbcTemplate.query(sql, new SpringMapper());
return list;
}
}
运行结果:
SpringVO [springId=1, springName=SpringIOC, springVersion=3.0]
SpringVO [springId=2, springName=SpringAOP, springVersion=3.5]
SpringVO [springId=3, springName=SpringJDBC, springVersion=3.8]
SpringVO [springId=4, springName=SpringTX, springVersion=4.2]
使用样板式语法,短短的几行代码,就得到了想要的结果,并且不需要关注连接池的开启与关闭以及其他繁琐的点,专心业务逻辑。