1.转账的描述
转账的过程有转出和收到,只有转出并且收到了才是一个完成的事物.所以只要转账过程中有一方发生错误,事物就必须回滚
2.在数据库中创建表
create table account(
id number primary key,
name varchar2(20),
balance number
);
insert into account values(1,'tom',10000.00);
insert into account values(2,'jerry',10000.00);
commit;
3.需要使用到的jar包
4.创建实体类
package db.bean;
public class Account {
private long id;
private String name;
private double balance;
public Account() {
// TODO Auto-generated constructor stub
}
public Account(long id, String name, double balance) {
super();
this.id = id;
this.name = name;
this.balance = balance;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
@Override
public String toString() {
return "Account [id=" + id + ", name=" + name + ", balance=" + balance + "]";
}
}
5.创建一个db.properties文件用来保存创建DataSource对象的信息
user,password和自己数据库保存相同
driver=oracle.jdbc.OracleDriver
url=jdbc:oracle:thin:@localhost:1521:XE
user=cyg
password=cyg
initSize=3
maxWait=3000
6.创建一个DBAppConfig类用来产生DataSource对象,jdbcTemplate对象和事物管理的对象
package db.config;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import com.alibaba.druid.pool.DruidDataSource;
//不用xml的配置,用java来进行配置要注释@Configuration表示这是一个spring配置类
@Configuration
//扫描包
@ComponentScan(basePackages= {"db.dao","db.service"})
//读取db.properties文件
@PropertySource(value = "classpath:db.properties")
//在转账的过程中可能会发生异常所以要启动事物管理
@EnableTransactionManagement
public class DBAppConfig {
@Value("${url}")
private String url;
@Value("${driver}")
private String driver;
@Value("${user}")
private String user;
@Value("${password}")
private String password;
@Value("${initSize}")
private int initSize;
@Value("${maxWait}")
private long maxWait;
//事物管理
@Bean
public DataSourceTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
//创建jdbcTemplate对象
@Bean(name = "jdbcTemplate")
public JdbcTemplate setDataSource(DataSource dataSource) {
//return new JdbcTemplate(dataSource);
return new JdbcTemplate(createDataSource());
}
//创建DataSource对象
@Bean(name = "dataSource")
public DataSource createDataSource() {
DruidDataSource ds = new DruidDataSource();
ds.setUrl(url);
ds.setDriverClassName(driver);
ds.setUsername(user);
ds.setPassword(password);
ds.setInitialSize(initSize);
ds.setMaxWait(maxWait);
return ds;
}
}
7.创建dao层的接口,以及其实现类
package db.dao;
import db.bean.Account;
public interface IAccountDao {
//通过id找account
Account findById(long id);
//修改余额
void updateBalanceId(double balance,long id);
//查看余额
double lookBalanceId(long id);
}
package db.dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import db.bean.Account;
//让其表明是一个受spring容器管理起来的持久层对象@Repository
@Repository
public class AccountDaoImpl implements IAccountDao{
@Autowired
JdbcTemplate temp;
@Override
public Account findById(long id) {
String sql = "select id,name,balance from account"
+ " where id = ?";
return temp.queryForObject(sql, (rs,rownum)->{
Account ac = new Account();
ac.setId(rs.getInt("id"));
ac.setName(rs.getString("name"));
ac.setBalance(rs.getDouble("balance"));
return ac;
},id);
}
@Override
public void updateBalanceId(double balance, long id) {
String sql = "update account set balance = ?"
+ " where id = ?";
temp.update(sql, balance,id);
}
@Override
public double lookBalanceId(long id) {
String sql = "select balance account"
+ " where id = ?";
return temp.queryForObject(sql, (rs,rownum)->{
Account ac = new Account();
ac.setBalance(rs.getDouble("balance"));
return ac.getBalance();
},id);
}
}
8.创建service层的接口和实现类
package db.service;
public interface IAccountService {
//from向to转账
void transforTo(int fromAccount,int toAccount,double money);
//查看两者的余额
void see(int fromAccount,int toAccount);
}
package db.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import db.bean.Account;
import db.dao.IAccountDao;
@Service
public class AccountServiceImpl implements IAccountService{
@Autowired
private IAccountDao accountDao;
//传入要转账人和收账人的id,以及转账金额
@Override
//添加事物管理如果转账过程中发生异常则回滚事物;
@Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
public void transforTo(int fromAccount, int toAccount, double money) {
Account from = accountDao.findById(fromAccount);
Account to = accountDao.findById(toAccount);
accountDao.updateBalanceId(10000, fromAccount);
accountDao.updateBalanceId(10000, toAccount);
if(from.getBalance()<money) {
throw new RuntimeException("账户余额不足!");
}
accountDao.updateBalanceId(from.getBalance()-money, fromAccount);
//假如在转账过程中有可能发生异常
double r = Math.random();
if(r<0.5) {
throw new RuntimeException("转账过程中有发生异常");
}
accountDao.updateBalanceId(to.getBalance()+money, toAccount);
}
//查看两人的余额
@Override
public void see(int fromAccount, int toAccount) {
Account from = accountDao.findById(fromAccount);
Account to = accountDao.findById(toAccount);
System.out.println("fromAccount的余额为:"+from.getBalance());
System.out.println("toAccount的余额为:"+to.getBalance());
}
}
9.为了在执行SQL语句时有日志输出写一个log4j.properties文件
log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d [%-5p] %c - %m%n
#只显示debug级别的SQL语句相关日志
log4j.logger.org.springframework.jdbc.core.JdbcTemplate=DEBUG
10.测试类
package spring_jd2007;
import java.util.Date;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import db.bean.Suser;
import db.config.DBAppConfig;
import db.dao.IUserDao;
import db.service.IAccountService;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = DBAppConfig.class)
public class DB_Test {
@Autowired
JdbcTemplate JdbcTemplate;
@Autowired
IAccountService accountService;
@Test
public void TestTransaction() {
accountService.transforTo(1, 2, 500);
accountService.see(1, 2);
}
}