Spring中的JdbcTemplate
pom.xml 添加坐标
org.springframework
spring-context
5.0.2.RELEASE
org.springframework
spring-jdbc
5.0.2.RELEASE
org.springframework
spring-tx
5.0.2.RELEASE
org.aspectj
aspectjweaver
1.8.7
mysql
mysql-connector-java
5.1.6
com.alibaba
druid
1.0.14
commons-dbutils
commons-dbutils
1.7
org.springframework
spring-test
5.0.2.RELEASE
junit
junit
4.12
test
com.zaxxer
HikariCP
3.1.0
Account.java
package perm.coco.bean;
import java.io.Serializable;
public class Account implements Serializable {
private Integer id;
private String name;
private Double money;
public Integer getId() {
return id;
}
public void setId(Integer 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;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
'}';
}
}
方式一 : 内置JDBC
可以使用 xml方式 或 注解方式
AccountDaoImpl.java
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import perm.coco.bean.Account;
import perm.coco.dao.AccountDao;
/**
* Spring 内置连接池
*/
public class AccountDaoImpl implements AccountDao {
/**
* 保存账户
* @param account
*/
@Override
public void save(Account account) {
//1.创建连接池(Spring内置的)
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///spring");
dataSource.setUsername("root");
dataSource.setPassword("root");
//1.创建JDBCTemplate对象
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
//操作数据库
String sql = "insert into account (id,name,money) values(?,?,?)";
jdbcTemplate.update(sql, account.getId(), account.getName(), account.getMoney());
}
}
applicationContext.xml
Test.java
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;
import perm.coco.bean.Account;
import perm.coco.dao.AccountDao;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = "classpath:applicationContext.xml")
public class AppTest {
//注入AccountDao
@Autowired
private AccountDao accountDao;
@Test
public void fun01() {
Account account = new Account();
account.setName("coco1");
account.setMoney(1002.0);
accountDao.save(account);
}
}
方式二: 继承 JdbcDaoSupport
只能使用xml方式,注解用不了
AccountDaoImpl02.java
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import perm.coco.bean.Account;
import perm.coco.dao.AccountDao;
/**
* 继承JdbcSuport
*/
public class AccountDaoImpl02 extends JdbcDaoSupport implements AccountDao {
/**
* 内置连接池
* 保存账户
* @param account
*/
@Override
public void save(Account account) {
//操作数据库
String sql = "insert into account (id,name,money) values(?,?,?)";
getJdbcTemplate().update(sql, account.getId(), account.getName(), account.getMoney());
}
}
applicationContext.xml
Test.java
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;
import perm.coco.bean.Account;
import perm.coco.dao.AccountDao;
import javax.annotation.Resource;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = "classpath:applicationContext.xml")
public class AppTest {
//注入AccountDao
@Resource(name = "accountDao02")
private AccountDao accountDao;
@Test
public void fun01() {
Account account = new Account();
account.setName("coco1");
account.setMoney(1002.0);
accountDao.save(account);
}
}
两种方式比较
第一种在Dao类中定义JdbcTemplate的方式,适用于所有配置方式(xml和注解都可以)
第二种让Dao继承JdbcDaoSupport的方式,只能用于基于XML的方式,注解用不了.
Spring 配置第三方连接池
c3p0
操作步骤:
- 在pom文件中添加c3p0坐标
- 在配置文件里面配置 c3p0
pom.xml
c3p0
c3p0
0.9.1.2
applicationContext.xml
AccountDaoImpl.java
package perm.coco.dao.Impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import perm.coco.bean.Account;
import perm.coco.dao.AccountDao;
/**
* c3p0 连接池
*/
@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {
@Autowired
private JdbcTemplate jdbcTemplate;
/**
* 保存账户
* @param account
*/
@Override
public void save(Account account) {
String sql = "insert into account (id,name,money) values (?,?,?) ";
jdbcTemplate.update(sql, account.getId(), account.getName(), account.getMoney());
}
}
Test.java
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;
import perm.coco.bean.Account;
import perm.coco.dao.AccountDao;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = "classpath:applicationContext.xml")
public class AppTest {
@Autowired
private AccountDao accountDao;
@Test
public void fun01() {
Account account = new Account();
account.setName("hahha");
account.setMoney(1000.0);
accountDao.save(account);
}
}
druid
pom.xml
com.alibaba
druid
1.1.10
applicationContext.xml
DBCP
HikariCP
pom.xml
com.zaxxer
HikariCP
3.1.0
applicationContext.xml
Spring引入 Properties配置文件
-
步骤
1.定义jdbc.properties文件
2.在spring核心配置文件里面引入配置文件
3.根据key获得值
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring
jdbc.username=root
jdbc.password=root
applicationContext.xml 页面使用
- 引入配置文件方式一(不推荐使用)
- 引入配置文件方式二
- bean标签中引用配置文件内容
注意:在使用
标签时,properties配置文件中的key一定要是带点分隔的。例如
jdbc.url
Spring管理事物
简介
由于Spring对持久层的很多框架都有支持 , Hibernate 、 jdbc 、 MyBatis 由于使用的框架不同,所以使用事务管理操作API 也不尽相同。 为了规范这些操作, Spring统一定义一个事务的规范 ,这其实是一个接口 。这个接口的名称 : PlatformTrasactionManager.并且它对已经做好的框架都有支持.
如果dao层使用的是JDBC 或者mybatis,那么 可以使用DataSourceTransactionManager 来处理事务
如果dao层使用的是 Hibernate, 那么可以使用HibernateTransactionManager 来处理事务
事务特性
- 原子型:事务是不可分割的工作单位,事务的操作要么都发生,要么都不发生
- 一致性:事务前后数据的完整性必须保持一致
- 隔离性:多个用户并发访问数据库时,一个用户的事务不能被其他用户的事务所干扰,多个并发事务之间数据要互相隔离
- 持久性:一个事务一旦被提交,它对数据库中数据的改变是永久性的。即使数据库发送故障也不应该对其有任何影响
事务的 API
声明事务管理机制(3个核心接口对象)
- PlatformTransactionManager 事务管理器
- commit 提交事务
- rollback 回滚
- getTransaction() 获取事务状态
- TransactionDefinition 事务定义信息
隔离级别
事务的传播行为
超时信息
只读
- TransactionStatus 事务具体运行状态
注意:事务结束,必须通过 commit。rollback是作为标记作为回滚。如果只是回滚,后面不操作,数据库与在关闭连接时,会自己commit
事务的传播行为
事务的传播行为的作用
我们一般都是将事务设置在Service层,那么当我们调用Service层的一个方法的时候, 它能够保证我们的这个方法中,执行的所有的对数据库的更新操作保持在一个事务中, 在事务层里面调用的这些方法要么全部成功,要么全部失败。
如果你的Service层的这个方法中,除了调用了Dao层的方法之外, 还调用了本类的其他的Service方法,那么在调用其他的Service方法的时候, 我必须保证两个service处在同一个事务中,确保事物的一致性。
事务的传播特性就是解决这个问题的。
事务的传播行为的取值
保证在同一个事务里面:
-
PROPAGATION_REQUIRED:默认值,也是最常用的场景.
如果当前没有事务,就新建一个事务,
如果已经存在一个事务中,加入到这个事务中。 -
PROPAGATION_SUPPORTS:
如果当前没有事务,就以非事务方式执行。
如果已经存在一个事务中,加入到这个事务中。
-
PROPAGATION_MANDATORY
如果当前没有有事务,就抛出异常;
如果已经存在一个事务中,加入到这个事务中。
保证不在同一个事物里:
-
PROPAGATION_REQUIRES_NEW
如果当前有事务,把当前事务挂起,创建新的事务但独自执行
-
PROPAGATION_NOT_SUPPORTED
如果当前存在事务,就把当前事务挂起。不创建事务
-
PROPAGATION_NEVER
如果当前存在事务,抛出异常
-
PROPAGATION_NESTED
嵌套事务 ,只对DataSourceTransactionManager有效 ,底层使用JDBC的SavePoint机制,允许在同一个事务设置保存点,回滚保存点
编程式事务管理
pom.xml
org.springframework
spring-context
5.0.2.RELEASE
org.springframework
spring-jdbc
5.0.2.RELEASE
org.aspectj
aspectjweaver
1.8.7
org.springframework
spring-tx
5.0.2.RELEASE
mysql
mysql-connector-java
5.1.6
org.springframework
spring-test
5.0.2.RELEASE
junit
junit
4.12
test
com.zaxxer
HikariCP
3.1.0
AccountServicesImpl.java
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
import perm.coco.dao.AccountDao;
import perm.coco.service.AccountService;
import sun.instrument.TransformerManager;
public class AccountServiceImpl implements AccountService {
//注入dao
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
//注入transactionTemplate
private TransactionTemplate transactionTemplate;
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}
@Override
public void transfer(String outUsername, String inUsername, Double money) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
//转出
accountDao.out(outUsername, money);
// int i = 1 / 0;
//转入
accountDao.in(inUsername, money);
}
});
}
public void transfer02(String outUsername, String inUsername, Double money) {
//1.创建数据源
HikariDataSource dataSource = new HikariDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/spring");
dataSource.setUsername("root");
dataSource.setPassword("root");
//1. 创建事务管理器
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(dataSource);
//创建事务管理器模板
TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
//转出
accountDao.out(outUsername, money);
// int i = 1 / 0;
//转入
accountDao.in(inUsername, money);
}
});
}
}
applicationContext.xml
声明事务管理-基于TransactionProxyFactoryBean
applicationContext.xml
PROPAGATION_REQUIRED
AccountServicesImpl.java
import perm.coco.dao.AccountDao;
import perm.coco.service.AccountService;
public class AccountServiceImpl implements AccountService {
//注入dao
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void transfer(String outUsername, String inUsername, Double money) {
//转出
accountDao.out(outUsername, money);
//int i = 1 / 0;
//转入
accountDao.in(inUsername, money);
}
}
声明事务管理-基于AspectJ(xml)
applicationContext.xml
AccountServiceImpl.xml
import perm.coco.dao.AccountDao;
import perm.coco.service.AccountService;
public class AccountServiceImpl implements AccountService {
//注入dao
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void transfer(String outUsername, String inUsername, Double money) {
//转出
accountDao.out(outUsername, money);
int i = 1 / 0;
//转入
accountDao.in(inUsername, money);
}
}
声明事务管理-注解
applicationContext.xml
AccountServiceImpl.java
package perm.coco.service.Impl;
import org.springframework.transaction.annotation.Transactional;
import perm.coco.dao.AccountDao;
import perm.coco.service.AccountService;
@Transactional
public class AccountServiceImpl implements AccountService {
//注入dao
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void transfer(String outUsername, String inUsername, Double money) {
//转出
accountDao.out(outUsername, money);
// int i = 1 / 0;
//转入
accountDao.in(inUsername, money);
}
}