【Spring】JDBC、AOP、事务

对于Spring来说,最重要的大概就是JDBC这一块知识了吧
牵扯到事务、AOP、IOC
正好这两天在学这个知识,整理了一下

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层,用来实现类的封装

扫描二维码关注公众号,回复: 11671281 查看本文章
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的删除改为以上代码,即可验证其合理性

猜你喜欢

转载自blog.csdn.net/qq_40915439/article/details/108329648