1.Spring 的 JDBC 的模板
Spring 提供了很多持久层技术的模板类简化编程:
1.使用Spring提供的jdbc模板操作数据库:首先引入spring-jdbc依赖和mysql的依赖
测试:
public class JDBCDemo1 {
@Test
public void test1()
{
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://192.168.203.130:3306/springboot?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull");
dataSource.setUsername("root");
dataSource.setPassword("******");
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.update("INSERT INTO account(account.`name`,money) VALUES (?,?)", " 会希 ",10000d);
}
}
配置Spring内置连接池:
<!-- 配置 Spring 的内置连接池 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClass}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 配置 JDBC 模板 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--引入外部的属性文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
新建配置文件:jdbc.properties
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://192.168.203.130:3306/springboot?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
jdbc.username=root
jdbc.password=*****
测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestSpring1 {
@Autowired
private JdbcTemplate jdbcTemplate;
@Test
public void testorder()
{
jdbcTemplate.update("INSERT INTO account(account.`name`,money) VALUES (?,?)", " 会希 ",10002d);
}
}
结果:
2.使用c3p0连接池:引入c3p0的依赖
修改Spring连接池配置文件:
<!--使用c3p0连接池-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestSpring1 {
@Autowired
private JdbcTemplate jdbcTemplate;
@Test
public void testorder()
{
jdbcTemplate.update("INSERT INTO account(account.`name`,money) VALUES (?,?)", " 会希 ",10003d);
}
}
结果:
2.事务
1. 什么是事务:事务逻辑上的一组操作,组成这组操作的各个逻辑单元,要么一起成功,要么一起失败.
2.事务特性:
原子性 :强调事务的不可分割.
一致性 :事务的执行的前后数据的完整性保持一致.
隔离性 :一个事务执行的过程中,不应该受到其他事务的干扰
持久性 :事务一旦结束,数据就持久到数据库
3.如果不考虑隔离性引发安全性问题
脏读 :一个事务读到了另一个事务的未提交的数据
不可重复读:一个事务读到了另一个事务已经提交的 update 的数据导致多次查询结果不一致
虚幻读:一个事务读到了另一个事务已经提交的 insert 的数据导致多次查询结果不一致.
4.解决读问题:设置事务隔离级别
未提交读 :脏读,不可重复读,虚读都有可能发生
已提交读 :避免脏读。但是不可重复读和虚读有可能发生
可重复读 :避免脏读和不可重复读.但是虚读有可能发生.
串行化的 :避免以上所有读问题
Mysql 默认:可重复读
Oracle 默认:读已提交
5.Spring 的这组接口是如何进行事务管理:平台事务管理根据事务定义的信息进行事务的管理,事务管理的过程中产生一些状态,将这些状态记录到 TransactionStatus 里面。
5.1PlatformTransactionManager:平台事务管理器
真正管理事务的对象
org.springframework.jdbc.datasource.DataSourceTransactionManager 使用 Spring JDBC 或 iBatis 进行持久化数据时使用
org.springframework.orm.hibernate3.HibernateTransactionManager 使用Hibernate 版本进行持久化数据时使用
5.2TransactionDefinition:事务定义信息
事务定义信息:
* 隔离级别
* 传播行为
* 超时信息
* 是否只读
5.3TransactionStatus:事务的状态
记录事务的状态
事务的传播行为:
* 保证同一个事务中
PROPAGATION_REQUIRED 支持当前事务,如果不存在 就新建一个(默认)
PROPAGATION_SUPPORTS 支持当前事务,如果不存在,就不使用事务
PROPAGATION_MANDATORY 支持当前事务,如果不存在,抛出异常
* 保证没有在同一个事务中
PROPAGATION_REQUIRES_NEW 如果有事务存在,挂起当前事务,创建一个新的事务
PROPAGATION_NOT_SUPPORTED 以非事务方式运行,如果有事务存在,挂起当前事务
PROPAGATION_NEVER 以非事务方式运行,如果有事务存在,抛出异常
PROPAGATION_NESTED 如果当前事务存在,则嵌套事务执行
理解事物的传播特性:
如果你在你的Service层的这个方法中,除了调用了Dao层的方法之外,还调用了本类的其他的Service方法,那么在调用其他的Service方法的时候,这个事务是怎么规定的呢,我必须保证我在我方法里掉用的这个方法与我本身的方法处在同一个事务中,否则如果保证事物的一致性。事务的传播特性就是解决这个问题的
默认情况下当发生RuntimeException的情况下,事务才会回滚,所以要注意一下 如果你在程序发生错误的情况下,有自己的异常处理机制定义自己的Exception,必须从RuntimeException类继承 这样事务才会回滚!
搭建一个转账的环境
创建一个账户对象Account
package com.wx.springsource1.pojo;
public class Account {
private String id;
private String name;
private Double money;
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;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
}
创建一个转账接口:
package com.wx.springsource1.service;
public interface AccountService {
//转账的方法
public void transfer(String from,String to,Double money);
public void outMoney(String from,Double money);
public void inMoney(String to,Double money);
}
实现转账方法:
package com.wx.springsource1.serviceimp;
import com.wx.springsource1.pojo.Account;
import com.wx.springsource1.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
public class AccountServiceImp implements AccountService {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void transfer(String from, String to, Double money) {
outMoney(from,money);
inMoney(to,money);
}
//A减少钱
public void outMoney(String from,Double money)
{
Account account = jdbcTemplate.queryForObject("SELECT * FROM account WHERE account.`name`=?", new MyRowMapper(),from);
jdbcTemplate.update("UPDATE account SET `money` = ?-? WHERE `name` = ?",account.getMoney(),money,account.getName());
}
//B账户增加钱
public void inMoney(String to,Double money)
{
Account account = jdbcTemplate.queryForObject("SELECT * FROM account WHERE account.`name`=?", new MyRowMapper(),to);
jdbcTemplate.update("UPDATE account SET `money` = ?+? WHERE `name` = ?",account.getMoney(),money,account.getName());
}
}
处理查询结果集:
package com.wx.springsource1.serviceimp;
import com.wx.springsource1.pojo.Account;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import java.sql.SQLException;
public class MyRowMapper implements RowMapper<Account> {
@Override
public Account mapRow(ResultSet resultSet, int i) throws SQLException {
Account account = new Account();
account.setId(resultSet.getString(1));
account.setName(resultSet.getString(2));
account.setMoney((Double)resultSet.getDouble(3));
return account;
}
}
配置Spring:
<bean id="orderDao" class="com.wx.springsource1.daoimp.OrderDaoImp"/>
测试:
package com.wx.springsource1.test;
import com.wx.springsource1.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestTx {
@Autowired
private AccountService accountService;
@Test
public void testtx()
{
accountService.transfer("aaa","bbb",100d);
}
}
加入事务的管理:Spring事务管理有三种实现方式,首先是手动编写代码实现事务管理,然后是xml配置事务管理核心思想史AOP,最后是注解式事务管理,最简单,也最常用,下面就使用注解式事务管理
1.添加约束文件,如果不添加,标签无法识别
2.配置事务管理器,这里使用Spring-jdbc的事务
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
3.开启注解式事务
<!--开启注解管理事务-->
<tx:annotation-driven transaction-manager="transactionManager"/>
4.在使用类或者方法上添加注解 @Transactional