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的删除改为以上代码,即可验证其合理性