在Spring中为了更加方便的操作JDBC,在JDBC的基础之上定义了一个抽象层,此设计的目的是为了给不同类型的JDBC操作提供模板方法,每个模板方法都能控制整个过程,并允许覆盖过程中的特定任务,通过这种方式尽可能的保留了灵活性,将数据库存取的工作量降到最低。
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.3.28version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.19version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.1.16version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-ormartifactId>
<version>5.3.28version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.13version>
<scope>testscope>
dependency>
db.driver=com.mysql.cj.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/trs-db?useUnicode=true&characterEncoding=utf8&tinyInt1isBit=false&useSSL=false&serverTimezone=GMT%2B8&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull
db.username=root
db.password=rootxq
<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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:property-placeholder location="classpath:db.properties">context:property-placeholder>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${db.driver}">property>
<property name="url" value="${db.url}">property>
<property name="username" value="${db.username}">property>
<property name="password" value="${db.password}">property>
bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource">property>
bean>
beans>
ClassPathXmlApplicationContext applicationContext = null;
@Before
public void before(){
applicationContext = new ClassPathXmlApplicationContext("spring-ioc-jdbc.xml");
}
@Test
public void queryForObject(){
//获取jdbcTemplate对象
JdbcTemplate jdbcTemplate = applicationContext.getBean(JdbcTemplate.class);
// 查询单个值
Long count = jdbcTemplate.queryForObject("select count(1) from users", Long.class);
System.out.println("查询结果:" + count);
//查询单个实体(实体属性与数据库字段名称一致)
User user1 = jdbcTemplate.queryForObject("select id ,u_name as name,salary from users where id = 1", new BeanPropertyRowMapper<>(User.class));
System.out.println(user1);
//查询单个实体(实体属性与数据库字段名称不一致)
User user2 = jdbcTemplate.queryForObject("select * from users where id = 2", (RowMapper<User>) (rs, rowNum) -> {
User u = new User();
u.setId(rs.getInt("id"));
u.setName(rs.getString("u_name"));
u.setSalary(rs.getDouble("salary"));
return u;
});
System.out.println(user2);
//查询列表(实体属性与数据库字段名称一致)
List<User> users = jdbcTemplate.query("select id ,u_name as name,salary from users", new BeanPropertyRowMapper<>(User.class));
System.out.println(users);
//查询列表(实体属性与数据库字段名称不一致)
List<User> users2 = jdbcTemplate.query("select * from users", (RowMapper<User>) (rs, rowNum) -> {
User u = new User();
u.setId(rs.getInt("id"));
u.setName(rs.getString("u_name"));
u.setSalary(rs.getDouble("salary"));
return u;
});
System.out.println(users2);
}
事务:是把一组业务当成一个业务来做,要么全都成功,要么全都失败,是保证业务操作完整性的一种数据库机制。
事务的ACID四大特性:
原子性
:在一组业务所有的操作步骤,要么全都成功,要么全都失败;一致性
:事务执行前后,要保证数据一致性,例如,两个人转账,转账前后他们的账户总额应该是不变的。隔离性
:在多个事务并发执行时,每个事务之间都是独立的,互不影响。持久性
:事务一旦执行成功,对数据的影响是不可逆的、永久性的。事务分为编程式事务
和声明式事务
两种:
PlatformTransactionManager
,它为事务管理封装了一组独立于技术的方法。无论使用Spring的哪种事务管理策略(编程式或声明式),事务管理器都是不可缺少的。
<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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:property-placeholder location="classpath:db.properties">context:property-placeholder>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${db.driver}">property>
<property name="url" value="${db.url}">property>
<property name="username" value="${db.username}">property>
<property name="password" value="${db.password}">property>
bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource">property>
bean>
<tx:annotation-driven transaction-manager="transactionManager">tx:annotation-driven>
beans>
@Transactional
设置事务隔离级别是为了解决并发事务过程中产生的一些问题,例如:脏读、幻读、不可重复读等等。
常见的事务问题:
事务隔离级别:
@Transactional(isolation = Isolation.DEFAULT)
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
@Transactional(isolation = Isolation.READ_COMMITTED)
@Transactional(isolation = Isolation.REPEATABLE_READ)
@Transactional(isolation = Isolation.SERIALIZABLE)
事务的传播特性指的是当一个事务方法被另一个事务方法调用(事务方法嵌套)时,需要指定事务应该如何传播。
/**
* 转账
*/
@Transactional
public void transferMoney(){
//扣款
subMoney();
//记录转账流水日志
addLog();
//加款
addMoney();
}
@Transactional
public void subMoney(){
System.out.println("扣除转账人的银行账户1000元");
}
public void addLog(){
System.out.println("记录转账的银行交易流水日志");
}
@Transactional
public void addMoney(){
System.out.println("收款人银行账户加款1000元");
}
此时,所有的方法都有事务,每个事务方法执行时事务应该怎么来控制?
REQUIRED(默认)
:
@Transactional(propagation = Propagation.REQUIRED)
SUPPORTS
:
@Transactional(propagation = Propagation.SUPPORTS)
REQUIRES_NEW
:
@Transactional(propagation = Propagation.REQUIRES_NEW)
NOT_SUPPORTED
:
@Transactional(propagation = Propagation.NOT_SUPPORTED)
NEVER
:
@Transactional(propagation = Propagation.NEVER)
MANDATORY
:
@Transactional(propagation = Propagation.MANDATORY)
NESTED
:
@Transactional(propagation = Propagation.NESTED)
@Transactional(timeout = 5)
@Transactional(readOnly = true)
@Transactional(rollbackFor = NullPointerException.class)
@Transactional(noRollbackkFor = NullPointerException.class)
<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:tx="http://www.springframework.org/schema/tx"
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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<aop:config>
<aop:pointcut id="transactionCutPoint" expression="execution(* org.example.mvc.impl.*.*(..))"/>
aop:config>
<tx:advice>
<tx:attributes>
<tx:method name="add*"/>
<tx:method name="update*" timeout="5" isolation="REPEATABLE_READ"/>
<tx:method name="query*" propagation="SUPPORTS"/>
<tx:method name="delete*" read-only="true"/>
tx:attributes>
tx:advice>
beans>