配置文件:
jdbc.driver=org.h2.Driver jdbc.url=jdbc:h2:file:~/.h2/h2 jdbc.username=root jdbc.password=123456
pom文件
xml version="1.0" encoding="UTF-8"?> <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/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0modelVersion> <groupId>org.examplegroupId> <artifactId>exampleartifactId> <version>1.0-SNAPSHOTversion> <packaging>jarpackaging> <dependencies> <dependency> <groupId>org.springframeworkgroupId> <artifactId>spring-contextartifactId> <version>5.2.7.RELEASEversion> dependency> <dependency> <groupId>commons-dbutilsgroupId> <artifactId>commons-dbutilsartifactId> <version>1.7version> dependency> <dependency> <groupId>com.h2databasegroupId> <artifactId>h2artifactId> <version>1.4.200version> dependency> <dependency> <groupId>c3p0groupId> <artifactId>c3p0artifactId> <version>0.9.1.2version> dependency> <dependency> <groupId>junitgroupId> <artifactId>junitartifactId> <version>4.12version> <scope>testscope> dependency> <dependency> <groupId>org.springframeworkgroupId> <artifactId>spring-testartifactId> <version>5.2.7.RELEASEversion> dependency> dependencies> <repositories> <repository> <id>alimavenid> <name>aliyun mavenname> <url>http://maven.aliyun.com/nexus/content/groups/public/url> <releases> <enabled>trueenabled> releases> <snapshots> <enabled>falseenabled> snapshots> repository> repositories> <properties> <project.build.sourceEncoding>UTF-8project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding> <java.version>14java.version> <maven.compiler.source>14maven.compiler.source> <maven.compiler.target>14maven.compiler.target> <encoding>UTF-8encoding> properties> project>
代码:
package com.example.config; import com.mchange.v2.c3p0.ComboPooledDataSource; import org.apache.commons.dbutils.QueryRunner; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.*; import javax.sql.DataSource; import java.beans.PropertyVetoException; @Configuration @ComponentScan("com.example") @PropertySource("classpath:jdbcConfig.properties") public class Config { @Value("${jdbc.driver}") private String driver; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String user; @Value("${jdbc.password}") private String pass; @Bean("runner") @Scope("prototype") public QueryRunner createQueryRunner(){ return new QueryRunner(); } @Bean("dataSource") public DataSource getDataSource() { ComboPooledDataSource dataSource = new ComboPooledDataSource(); try { dataSource.setDriverClass(driver); } catch (PropertyVetoException e) { throw new RuntimeException(e); } dataSource.setJdbcUrl(url); dataSource.setUser(user); dataSource.setPassword(pass); return dataSource; } }
package com.example.domain; import java.io.Serializable; /** * 账户的实现类 */ public class Account implements Serializable { private int id; private String name; private float money; public Account() {} public Account(String name, int money) { this.name=name; this.money=money; } public Account(int id, String name, int money) { this.id=id; this.name=name; this.money=money; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public float getMoney() { return money; } public void setMoney(float money) { this.money = money; } @Override public String toString() { return "Account{" + "id=" + id + ", name='" + name + '\'' + ", money=" + money + '}'; } }
package com.example.utils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; /** * 连接工具类,他用于从数据源中获取一个连接,并实现和线程绑定 */ @Component public class ConnectionUtils { private ThreadLocaltl = new ThreadLocal (); @Autowired private DataSource dataSource; public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; } /** * 获取线程上的链接 * @return */ public Connection getThreadConnection(){ //1. 先从ThreadLocal上获取 Connection conn=tl.get(); //2. 判断当前线程上是否有链接 if(conn==null){ //3. 从数据源中获取一个连接,并存入TreadLocal中 try { conn=dataSource.getConnection(); tl.set(conn); } catch (SQLException throwables) { throw new RuntimeException(throwables); } } //4. 返回当前线程上的链接 return conn; } /** * 把链接和线程解绑 */ public void removeConnection(){ tl.remove(); } }
package com.example.utils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.sql.SQLException; /** * 和事务管理相关的工具类,它包含了,开启事务,提交事务,回滚事务和是放链接 */ @Component public class TransactionManager { int i=0; @Autowired private ConnectionUtils connectionUtils; public void setConnectionUtils(ConnectionUtils connectionUtils) { this.connectionUtils = connectionUtils; } /** * 开启事务 */ public void beginTransaction(){ try { connectionUtils.getThreadConnection().setAutoCommit(false); i--; } catch (SQLException throwables) { throwables.printStackTrace(); } } /** * 提交事务 */ public void commit(){ if(i<0){ i++; return; } try { connectionUtils.getThreadConnection().commit(); } catch (SQLException throwables) { throwables.printStackTrace(); } } /** * 回滚事务 */ public void rollback(){ try { connectionUtils.getThreadConnection().rollback(); i=0; } catch (SQLException throwables) { throwables.printStackTrace(); } } /** * 释放事务 */ public void release(){ if(i<0)return; try { connectionUtils.getThreadConnection().close(); connectionUtils.removeConnection(); } catch (SQLException throwables) { throwables.printStackTrace(); } } }
package com.example.service; import com.example.domain.Account; import java.util.List; /** * 账户的业务层接口 */ public interface IAccountService { /** * 查询所有 * @return */ ListfindAllAccount(); /** * 查询一个 * @param id * @return */ Account findAccountById(int id); /** * 保存账户 * @param account */ void saveAccount(Account account); /** * 更新账户 * @param account */ void updateAccount(Account account); /** * 删除账户 * @param id */ void deleteAccount(int id); /** * 转账 * @param sourceName * @param targetName * @param money */ void transfer(String sourceName,String targetName,float money); }
package com.example.service.impl; import com.example.dao.IAccountDao; import com.example.domain.Account; import com.example.service.IAccountService; import com.example.utils.TransactionManager; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service("accountService") public class AccountServiceImpl implements IAccountService { @Autowired private IAccountDao accountDao; @Autowired private TransactionManager tm; public IAccountDao getAccountDao() { return accountDao; } public void setAccountDao(IAccountDao accountDao) { this.accountDao = accountDao; } @Override public ListfindAllAccount() { List accounts=null; tm.beginTransaction(); try{ accounts= accountDao.findAllAccount(); tm.commit(); }catch (Exception e){ tm.rollback(); e.printStackTrace(); }finally { tm.release(); } return accounts; } @Override public Account findAccountById(int id) { return accountDao.findAccountById(id); } @Override public void saveAccount(Account account) { tm.beginTransaction(); try{ accountDao.saveAccount(account); tm.commit(); }catch (Exception e){ tm.rollback(); e.printStackTrace(); }finally { tm.release(); } } @Override public void updateAccount(Account account) { tm.beginTransaction(); try{ accountDao.updateAccount(account); tm.commit(); }catch (Exception e){ tm.rollback(); e.printStackTrace(); }finally { tm.release(); } } @Override public void deleteAccount(int id) { tm.beginTransaction(); try{ accountDao.deleteAccount(id); tm.commit(); }catch (Exception e){ tm.rollback(); e.printStackTrace(); }finally { tm.release(); } } @Override public void transfer(String sourceName, String targetName, float money) { tm.beginTransaction(); try { //1. 根据名称查询转出账户 Account sourceAccount = accountDao.findAccountByName(sourceName); System.out.println(sourceAccount); //2. 根据名称查询转入账户 Account targetAccount = accountDao.findAccountByName(targetName); System.out.println(targetAccount); //3. 转出账户减钱 sourceAccount.setMoney(sourceAccount.getMoney() - money); System.out.println(sourceAccount); //4. 转入账户加钱 targetAccount.setMoney(targetAccount.getMoney() + money); System.out.println(targetAccount); //5. 更新转出账户 updateAccount(sourceAccount); int i=1/0; //6. 更新转入账户 updateAccount(targetAccount); tm.commit(); }catch (Exception e){ tm.rollback(); e.printStackTrace(); }finally { tm.release(); } } }
package com.example.dao; import com.example.domain.Account; import java.util.List; /** * 账户的持久层接口 */ public interface IAccountDao { /** * 查询所有 * @return */ ListfindAllAccount(); /** * 查询一个 * @param id * @return */ Account findAccountById(int id); /** * 保存账户 * @param account */ void saveAccount(Account account); /** * 更新账户 * @param account */ void updateAccount(Account account); /** * 删除账户 * @param id */ void deleteAccount(int id); /** * 通过名称查账户,唯一 * @param accoutName * @return */ Account findAccountByName(String accoutName); }
package com.example.dao.impl; import com.example.dao.IAccountDao; import com.example.domain.Account; import com.example.utils.ConnectionUtils; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.handlers.BeanHandler; import org.apache.commons.dbutils.handlers.BeanListHandler; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Repository; import java.sql.SQLException; import java.util.List; /** * 账户的持久层实现类 */ @Repository public class AccountDaoImpl implements IAccountDao { @Autowired private QueryRunner runner; @Autowired private ConnectionUtils connectionUtils; public QueryRunner getRunner() { return runner; } public void setRunner(QueryRunner runner) { this.runner = runner; } @Override public ListfindAllAccount() { try { return runner.query(connectionUtils.getThreadConnection(),"select * from account",new BeanListHandler (Account.class)); } catch (SQLException throwables) { throw new RuntimeException(throwables); } } @Override public Account findAccountById(int id) { try { return runner.query(connectionUtils.getThreadConnection(),"select * from account where id = ?",new BeanHandler (Account.class),id); } catch (SQLException throwables) { throw new RuntimeException(throwables); } } @Override public void saveAccount(Account account) { try { runner.update(connectionUtils.getThreadConnection(),"insert into account(name,money)values(?,?)",account.getName(),account.getMoney()); } catch (SQLException throwables) { throw new RuntimeException(throwables); } } @Override public void updateAccount(Account account) { try { runner.update(connectionUtils.getThreadConnection(),"update account set name =?,money=? where id =?",account.getName(),account.getMoney(),account.getId()); } catch (SQLException throwables) { throw new RuntimeException(throwables); } } @Override public void deleteAccount(int id) { try { runner.update(connectionUtils.getThreadConnection(),"delete account where id = ?",id); } catch (SQLException throwables) { throw new RuntimeException(throwables); } } @Override public Account findAccountByName(String accoutName) { try { List accounts=runner.query(connectionUtils.getThreadConnection(),"select * from account where name = ?",new BeanListHandler (Account.class),accoutName); if(accounts==null||accounts.size()==0){ return null; }else if(accounts.size()>1){ throw new RuntimeException("结果集不唯一,数据有问题"); }else { return accounts.get(0); } } catch (SQLException throwables) { throw new RuntimeException(throwables); } } }
测试:
package com.example; import com.example.config.Config; import com.example.domain.Account; import com.example.service.IAccountService; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import java.util.List; /** * Spring整合JUnit单元测试,测试我们的配置 */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = Config.class) public class AccountServiceTest { @Autowired IAccountService as; @Test public void testFindAll() { Listaccounts = as.findAllAccount(); for(Account account : accounts){ System.out.println(account); } } @Test public void testFindOne() { Account account=as.findAccountById(1); System.out.println(account); } @Test public void testSave() { Account account=new Account("account4",100); as.saveAccount(account); } @Test public void testTransfer() { as.transfer("account1","account3",100); } @Test public void testUpdate() { Account account=new Account(3,"ddd",100); as.updateAccount(account); } @Test public void testDelete() { as.deleteAccount(2); } }