对于Spring来说,最重要的大概就是JDBC这一块知识了吧
牵扯到事务、AOP、IOC
正好这两天在学这个知识,整理了一下
目录
- 1. Spring中JDBC简介
- 2. Spring的配置
- 2.1 pom.xml
- 2.2 数据库连接池
- 2.2.1 JDBC连接池
- 2.2.2 C3P0连接池
- 2.2.3 DBCP连接池
- 2.2.4 jdbc.properties文件
- 2.2.4 总配置文件
- 3. Java端
- 3.1 TestModel
- 3.2 SpringDao
- 3.2.1 注入的操作
- 3.2.2 增删改的操作
- 3.3.3 查找的操作
- 3.3 Main(类似Service层,主要进行测试用)
- 4. AOP、事务
- 4.1 事务的配置
- 4.2 配置另外的类
- 4.3 事务的实现
- 4.4 事务的验证
1. Spring中JDBC简介
个人感觉Spring中的JDBC简化了我们之前手写JDBC的步骤,实现了代码的简洁与条理性
如下所示:
public int insert() {
String sql = "insert into test(id, name)values(?,?)";
return jdbcTemplate.update(sql, "1", "2");
}
public int update() {
String sql = "update test set name = ? where id = ?";
return jdbcTemplate.update(sql, "3", "1");
}
public int delete(String id) {
String sql = "delete from test where id = ?";
return jdbcTemplate.update(sql, id);
}
public List<TestModel> selectList() {
String sql = "select id, name from test where id=?";
return jdbcTemplate.query(sql, new Object[] { 15 }, new ModelMapper());
}
基本直接一条语句就可以进行配置,完成数据库的增删改查
因此,我们来看一下具体的配置方法及应用
2. Spring的配置
2.1 pom.xml
首先就是总体xml文件的配置了,主要引进依赖及各种包
== 需要注意的是:我们spring-webmvcspring-jdbc的版本必须保持一致==
z<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>situ</groupId>
<artifactId>test3</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>test3 Maven Webapp</name>
<url>http://maven.apache.org</url>
<!-- 依赖 -->
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.20</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.json/json -->
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20160810</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.1</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
</dependencies>
<build>
<finalName>test3</finalName>
</build>
</project>
2.2 数据库连接池
我们在配置完总体xml之后,需要进行数据源的注入
在Spring中有3中注入的方法:JDBC、C3P0、DBCP
2.2.1 JDBC连接池
对于JDBC来说,他属于Spring的内置连接池
配置条件如下:
<!-- 引入属性文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置Spring内置的连接池 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!-- 引入属性文件的值 -->
<property name="driverClassName" value="${driverClass}"></property>
<property name="url" value="${jdbcUrl}"></property>
<property name="username" value="${user}"></property>
<property name="password" value="${password}"></property>
</bean>
<!-- 配置spring的JDBC的模版 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
2.2.2 C3P0连接池
<!-- 引入属性文件 -->
<context:property-placeholder location="classpath:JDBC.properties"/>
<!-- 配置C3P0连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- 引入属性文件的值 -->
<property name="driverClass" value="${driverClass}"></property>
<property name="jdbcUrl" value="${jdbcUrl}"></property>
<property name="user" value="${user}"></property>
<property name="password" value="${password}"></property>
</bean>
<!-- 配置spring的JDBC的模版 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
2.2.3 DBCP连接池
<!-- 引入属性文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置DBCP连接池 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<!-- 引入属性文件的值 -->
<property name="driverClassName" value="${driverClass}"></property>
<property name="url" value="${jdbcUrl}"></property>
<property name="username" value="${user}"></property>
<property name="password" value="${password}"></property>
</bean>
<!-- 配置spring的JDBC的模版 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
2.2.4 jdbc.properties文件
user=root
password=123456
minPoolSize=5
maxPoolSize=20
initialPoolSize=5
driverClass=com.mysql.cj.jdbc.Driver
jdbcUrl=jdbc:mysql://127.0.0.1:3308/work?useSSL=false&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=Hongkong&allowPublicKeyRetrieval=true
2.2.4 总配置文件
<?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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
default-autowire="byName">
<context:annotation-config />
<context:component-scan base-package="service" />
<context:property-placeholder
location="classpath:JDBC.properties" />
<!-- 数据源 -->
<!-- <bean id="dataSource" -->
<!-- class="org.springframework.jdbc.datasource.DriverManagerDataSource"> -->
<!-- <property name="driverCLassName" value="${driverClass}" /> -->
<!-- <property name="url" value="${jdbcUrl}" /> -->
<!-- <property name="username" value="${user}" /> -->
<!-- <property name="password" value="${pass}" /> -->
<!-- </bean> -->
<bean id="dataSource"
class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${driverClass}" />
<property name="jdbcUrl" value="${jdbcUrl}" />
<property name="user" value="${user}" />
<property name="password" value="${password}" />
<property name="minPoolSize" value="${minPoolSize}"></property>
<property name="maxPoolSize" value="${maxPoolSize}"></property>
<property name="initialPoolSize" value="${initialPoolSize}"></property>
</bean>
<bean id="springJdbc1" class="service.SpringJdbc1"></bean>
<!--生成JdbcTemplate -->
<!--直接使用XML进行注入 -->
<bean id="jdbcTemplate2"
class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="SpringDao" class="service.SpringDao"></bean>
<bean id="Dao1" class="service.Dao1"></bean>
</beans>
3. Java端
3.1 TestModel
最底层的Model层,用来实现类的封装
package service;
public class TestModel {
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "TestModel [id=" + id + ", name=" + name + "]";
}
}
3.2 SpringDao
这一层主要是利用JdbcTemplate
提供的增删改查来实现对数据库的操作
3.2.1 注入的操作
@Autowired
@Qualifier("jdbcTemplate2")
private JdbcTemplate jdbcTemplate;
这里使用Autowired + Qualifier(“jdbcTemplate2”),是将我们在context3中进行的XML注入拿过来使用注入private JdbcTemplate jdbcTemplate;
这个里面
<bean id="jdbcTemplate2"
class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
3.2.2 增删改的操作
public int insert() {
String sql = "insert into test(id, name)values(?,?)";
return jdbcTemplate.update(sql, "1", "2");
}
public int update() {
String sql = "update test set name = ? where id = ?";
return jdbcTemplate.update(sql, "3", "1");
}
public int delete(String id) {
String sql = "delete from test where id = ?";
return jdbcTemplate.update(sql, id);
}
3.3.3 查找的操作
对于查找来说,使用的是jdbcTemplate.query
我们来看一下:
第一个参数sql:数据库语句
第二个参数:一个Object的数组,也就是填充我们的问号
第三个参数:ModelMapper(映射)
public List<TestModel> selectList() {
String sql = "select id, name from test where id=?";
return jdbcTemplate.query(sql, new Object[] { 15 }, new ModelMapper());
}
我们重点来看一下这个映射
对于映射而言,我们首先要知道这是干什么的?
我们知道,查询和增删改最大的操作不同就是它多一步返回ModelList值的操作,也就是ResultSet rs的获取
所以,我们需要获取这个ModelList,来进行返回
import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.jdbc.core.RowMapper;
public class ModelMapper implements RowMapper<TestModel> {
// 映射ORM
// 查询出来的值来进行赋值
// 查询几条记录 就会映射几次
public TestModel mapRow(ResultSet rs, int rowNum) throws SQLException {
TestModel testModel = new TestModel();
testModel.setId(rs.getString("id"));
testModel.setName(rs.getString("name"));
return testModel;
}
}
因为我们返回的是一个集合,所以,集合里面有几条数据,就映射几次
另一种写法(内部类)
public List<TestModel> selectList2() {
String sql = "select id, name from test where 1=1";
return jdbcTemplate.query(sql, new Object[] { 15 }, new ModelMapper() {
public TestModel mapRow(ResultSet rs, int rowNum) throws SQLException {
TestModel testModel = new TestModel();
testModel.setId(rs.getString("id"));
testModel.setName(rs.getString("name"));
return testModel;
}
});
}
当然,我们也进行查询后返回别的值,如下:
public void queryForObject() {
String sql = "select id, name from test where id=?";
TestModel model = jdbcTemplate.queryForObject(sql, new Object[] { 15 }, new ModelMapper());
System.out.println(model);
String sql2 = "select id, name from test where id=?";
String name = jdbcTemplate.queryForObject(sql2, new Object[] { 1 }, String.class);
System.out.println(name);
}
第一种利用queryForObject
来返回一个Model进行输出
第二种利用String.class
加载String的类,进行反射
3.3 Main(类似Service层,主要进行测试用)
- 通过
ApplicationContext context = new ClassPathXmlApplicationContext("context3.xml");
创里连接 - 获取SpringDao的对象
context.getBean("SpringDao")
- 最后,调用
dao.test()
进行输出
<bean id="SpringDao" class="service.SpringDao"></bean>
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("context3.xml");
SpringDao dao = (SpringDao) context.getBean("SpringDao");
dao.test();
// 输出111
}
}
4. AOP、事务
== AOP是个啥?==
专业术语:面向切面编程
通俗提懂:我们把每一个层分开,在每一个层进行操作,如事务
== 事务是啥呢?==
这里简单说一下,我所理解的事务也就是:
比如一个部门表,一个成员表,当部门表被删除时,我们也要删除相对应的成员信息,也就是执行两条SQL语句
假如这时候我们把部门表给删除了,我们再去删除成员表中的信息时,出现了一点小意外,导致我们成员表信息没办法删除,这时候就尴尬了~
部门表已经没了,可成员对应的部门还存在,这。。。。有点匪夷所思
所以,我们用事务来解决这个问题
我们把所有的要执行的SQL语句放在一个事务中,假如其中有一个报错,则直接进行回滚,我们之前执行的所有的操作语句都还原,这样就可以避免上述尴尬情况的发生。
4.1 事务的配置
对于事务来说,我们也需要进行文件的配置
<?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:tx="http://www.springframework.org/schema/tx"
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.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd"
default-autowire="byName">
<bean id="dao1" class="service.Dao1" />
<bean id="springDao" class="service.SpringDao" />
<bean id="service1" class="service.Serivce1" />
<!-- 事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
<!-- 需要管理的数据源 -->
</bean>
<tx:advice id="advice"
transaction-manager="transactionManager">
<tx:attributes>
<!-- <tx:method name="*" propagation="REQUIRED" /> -->
<tx:method name="delete*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="insert*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<!-- 用切点把事务切进去 -->
<aop:config>
<aop:pointcut expression="execution(* service.*.*(..))"
id="pointcut" />
<aop:advisor advice-ref="advice" pointcut-ref="pointcut" />
</aop:config>
</beans>
第一部分,也就是事务管理器,这个是干啥的呢?
我们在上面从数据池中拿出来的东西,也就是数据源,要在这进行管理
这里我们使用了别的xml文件的内容,我们怎么可以使用的呢?
建立一个spring.xml,将两个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"
xmlns:p="http://www.springframework.org/schema/p"
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.xsd"
default-autowire="byName">
<context:annotation-config />
<context:component-scan base-package="service" />
<import resource="context3.xml"></import>
<import resource="test3.xml"></import>
</beans>
第二部分,我们规定的操作,这里注意一下:name="delete*"
这个*号的意思,也就以delete开头所有方法
第三部分,利用AOP切片,将事务切入进去,execution(* service.*.*(..))
意思为:service包下的任意类下的任意方法的任意参数
4.2 配置另外的类
和上面差不多,主要就是修改一下Dao层里关于SQL语句的书写
我们在定义一个Model2,一个Dao2
Model2
package service;
public class TestModel2 {
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "TestModel [id=" + id + ", name=" + name + "]";
}
}
Dao2
package service;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
public class Dao1 {
@Autowired
@Qualifier("jdbcTemplate2")
private JdbcTemplate jdbcTemplate;
public void test1() {
System.out.println("111");
}
public int insert() {
String sql = "insert into test1(id, name)values(?,?)";
return jdbcTemplate.update(sql, "1", "2");
}
public int update() {
String sql = "update test1 set name = ? where id = ?";
return jdbcTemplate.update(sql, "3", "1");
}
public int delete(String id) {
String sql = "delete from test1 where id = ?";
return jdbcTemplate.update(sql, id);
}
// 三个参数
// sql : SQL语句
// Object : 你要赋值的一个数组
public List<TestModel> selectList() {
String sql = "select id, name from test1 where id=?";
return jdbcTemplate.query(sql, new Object[] { 15 }, new ModelMapper());
}
// 内部类的写法
public List<TestModel> selectList2() {
String sql = "select id, name from test1 where 1=1";
return jdbcTemplate.query(sql, new Object[] { 15 }, new ModelMapper() {
public TestModel mapRow(ResultSet rs, int rowNum) throws SQLException {
TestModel testModel = new TestModel();
testModel.setId(rs.getString("id"));
testModel.setName(rs.getString("name"));
return testModel;
}
});
}
public void queryForObject() {
String sql = "select id, name from test1 where id=?";
TestModel model = jdbcTemplate.queryForObject(sql, new Object[] { 15 }, new ModelMapper());
System.out.println(model);
String sql2 = "select id, name from test1 where id=?";
String name = jdbcTemplate.queryForObject(sql2, new Object[] { 1 }, String.class);
System.out.println(name);
}
}
4.3 事务的实现
到了最后一步,也就是真正实现我们的事务
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Serivce1 {
@Autowired
private SpringDao springDao;
@Autowired
private Dao1 dao1;
public void delete(String id) {
dao1.delete(id);
springDao.delete(id);
}
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
Serivce1 serivce1 = (Serivce1) context.getBean("service1");
serivce1.delete("1");
}
}
对于下面这两段代码,主要就是注入Dao1和SpringDao
@Autowired
private SpringDao springDao;
@Autowired
private Dao1 dao1;
下面代码
- 调用spring.xml文件
- 获取service1的实例化
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
Serivce1 serivce1 = (Serivce1) context.getBean("service1");
serivce1.delete("1");
}
最后事务成功实现
4.4 事务的验证
public int delete(String id) {
if (id.equals("1")) {
int n = 1 / 0;
}
String sql = "delete from test1 where id = ?";
return jdbcTemplate.update(sql, id);
}
将Dao的删除改为以上代码,即可验证其合理性