一、学习目标
- 理解ThreadLocal工具类使用
- 使用spring的aop增强事务
- 了解jdbcTemplate工具类
二、spring的aop完成事务控制
2.0转账逻辑环境搭建
2.0.1 创建项目导入maven依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.9</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<!-- junit版本至少是4.12以上-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- 导入aop编程需要的包-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
2.0.1 编写spring配置文件
<?xml version="1.0" encoding="UTF-8"?>
<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: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/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--
通过包扫描的方式 告诉spring框架 我的东西都在哪个包下放着呢
多个包 以,分割开来
所谓包扫描 原理就是找到那个文件遍历文件夹 查找这个文件夹的所有的文件名
-->
<context:component-scan base-package="com.itheima.service,com.itheima.dao"></context:component-scan>
<!--
配置外部properties属性位置信息
classpath: 类路径的意思
-->
<context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
<!--
配置druid的数据库连接池
功能最全的 性能优势就牛逼的
-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
</beans>
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring
jdbc.username=root
jdbc.password=123456
2.0.2 编写service,dao,pojo 和数据库表的创建
service代码
package com.itheima.service;
import com.itheima.pojo.Account;
public interface AccountService {
void save(Account account);
Account findById(int id);
void update(Account account);
void del(int id);
void transfer(int from,int to,double money);
}
package com.itheima.service.impl;
import com.itheima.dao.AccountDao;
import com.itheima.pojo.Account;
import com.itheima.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
@Autowired
private DataSource dataSource;
@Override
public void save(Account account) {
accountDao.save(account);
}
@Override
public Account findById(int id) {
return accountDao.findById(id);
}
@Override
public void update(Account account) {
accountDao.update(account);
}
@Override
public void del(int id) {
accountDao.del(id);
}
@Override
public void transfer(int from, int to, double money) {
accountDao.updateMoney(from,-money);
accountDao.updateMoney(to,money);
}
}
dao代码
package com.itheima.dao;
import com.itheima.pojo.Account;
import java.sql.Connection;
public interface AccountDao {
void save(Account account);
Account findById(int id);
void update(Account account);
void del(int id);
void updateMoney(int id,double money);
}
package com.itheima.dao.impl;
import com.itheima.dao.AccountDao;
import com.itheima.pojo.Account;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
@Repository
public class AccountDaoImpl implements AccountDao {
@Autowired
private DataSource dataSource;
@Override
public void save(Account account,Connection connection) {
System.out.println("带上数据库一起玩");
}
@Override
public Account findById(int id) {
//真是跟数据库交互的
return new Account();
}
@Override
public void update(Account account) {
System.out.println("正在更新账户信息");
}
@Override
public void del(int id) {
System.out.println("正在根据id删除账户信息");
}
@Override
public void updateMoney(int id, double money) {
System.out.println("转账逻辑");
}
}
pojo代码
package com.itheima.pojo;
/**
* @author Administrator
* @TIME 2020/7/4 9:38
* @description
*/
public class Account {
private int id;
private String name;
private double 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 double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
}
sql语句
CREATE TABLE `account` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL,
`money` double DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
insert into `account`(`id`,`name`,`money`) values
(1,'小户',1000),
(2,'小明',1000);
2.1 不带事务控制的转账逻辑
修改dao代码 注入datasource对象 完成数据库操作
public void updateMoney(int id, double money) {
Connection connection=null;
PreparedStatement preparedStatement=null;
try {
connection=dataSource.getConnection();
//获取statement对象
preparedStatement = connection.prepareStatement("update account set money=money+? where id=?");
//设置参数
preparedStatement.setObject(1,money);
preparedStatement.setObject(2,id);
//执行
preparedStatement.execute();
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
//关闭资源
try {
if (preparedStatement!=null){
preparedStatement.close();
}
if (connection!=null){
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
上述代码不带有任何的事务控制 不能完成对于事务的操作
2.2 传递connection对象带有事务控制的转账逻辑
事务控制应该交给service代码来控制 保证一个业务中应该使用同一个连接对象
2.2.1 修改service代码
package com.itheima.service.impl;
import com.itheima.dao.AccountDao;
import com.itheima.pojo.Account;
import com.itheima.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
//注入datasource
@Autowired
private DataSource dataSource;
@Override
public void save(Account account) {
accountDao.save(account);
}
@Override
public Account findById(int id) {
return accountDao.findById(id);
}
@Override
public void update(Account account) {
accountDao.update(account);
}
@Override
public void del(int id) {
accountDao.del(id);
}
@Override
public void transfer(int from, int to, double money) {
//保证接下来操作 都处于同一个事物中
//事务控制基于 连接的对象
Connection connection=null;
try {
connection = dataSource.getConnection();
//修改手动提交事务
connection.setAutoCommit(false);
accountDao.updateMoney(from,-money,connection);
int i=5/0;
accountDao.updateMoney(to,money,connection);
//提交事务
connection.commit();
} catch (SQLException e) {
e.printStackTrace();
try {
//回滚事务
connection.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}finally {
if (connection!=null){
try {
//关闭资源
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
2.2.2 修改dao代码
package com.itheima.dao.impl;
import com.itheima.dao.AccountDao;
import com.itheima.pojo.Account;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
@Repository
public class AccountDaoImpl implements AccountDao {
//它就不需要datasource了
//@Autowired
//private DataSource dataSource;
@Override
public void save(Account account) {
System.out.println("带上数据库一起玩");
}
@Override
public Account findById(int id) {
//真是跟数据库交互的
return new Account();
}
@Override
public void update(Account account) {
System.out.println("正在更新账户信息");
}
@Override
public void del(int id) {
System.out.println("正在根据id删除账户信息");
}
@Override
public void updateMoney(int id, double money,Connection connection) {
PreparedStatement preparedStatement=null;
try {
//获取statement对象
preparedStatement = connection.prepareStatement("update account set money=money+? where id=?");
//设置参数
preparedStatement.setObject(1,money);
preparedStatement.setObject(2,id);
//执行
preparedStatement.execute();
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
//关闭资源
try {
if (preparedStatement!=null){
preparedStatement.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
通过传递connetion对象的方式 保证多个dao操作使用同一个连接对象
2.3 使用ThreadLocal工具完成事务控制的转账逻辑
上述代码已经可以控制事务了 但是需要往dao层传递connection对象 这个本来跟业务无关的对象
我们可以将这个对象放入到当前线程里 无需传递该参数 简化编写逻辑
2.3.1 使用ThreadLocal的前提条件
羡慕编写完毕之后 要部署到tomcat中运行 tomcat运行机制就是每一个请求一个线程
无论web层代码还是service代码已经dao代码 都会在一个线程执行 可以将连接对象放入当前线程
2.3.2 ThreadLocal工具类api演示
package com.itheima.utils;
import java.sql.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;
public class ConnectionUtils {
public static void main(String[] args) {
//怎么往线程中放置属性
//它是jdk提供给我们 用来往当前线程中放置变量的一个工具类
ThreadLocal<String> threadLocal_str=new ThreadLocal();
threadLocal_str.set("你好");
String s = threadLocal_str.get();
System.out.println(s);
ThreadLocal<String[]> threadLocalArr = new ThreadLocal<>();
threadLocalArr.set(new String[]{"抽烟","喝酒","烫头"});
String[] arr = threadLocalArr.get();
System.out.println(Arrays.toString(arr));
//注意threadLocal对象的特色 谁放进去 谁取出来
//注意threadLocal对象的特色 谁放进去 谁取出来
//注意threadLocal对象的特色 谁放进去 谁取出来
//注意threadLocal对象的特色 谁放进去 谁取出来
//注意threadLocal对象的特色 谁放进去 谁取出来
}
}
2.3.3 利用threadlocal工具类编写连接工具类
package com.itheima.utils;
import java.sql.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;
public class ConnectionUtils {
private static ThreadLocal<Connection> threadLocal=new ThreadLocal();
//讲连接放入到当前线程中
public static void setConnection(Connection connection){
threadLocal.set(connection);
}
//获取当前线程的连接
public static Connection getConnection(){
return threadLocal.get();
}
//从当前线程移除
public static void removeConnetion(){
threadLocal.remove();
}
}
2.3.4 修改service代码和dao代码
package com.itheima.service.impl;
import com.itheima.dao.AccountDao;
import com.itheima.pojo.Account;
import com.itheima.service.AccountService;
import com.itheima.utils.ConnectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
@Autowired
private DataSource dataSource;
@Override
public void save(Account account) {
//保证接下来操作 都处于同一个事物中
//事务控制基于 连接的对象
Connection connection=null;
try {
connection = dataSource.getConnection();
//修改手动提交事务
connection.setAutoCommit(false);
accountDao.save(account,connection);
//int i=5/0;
accountDao.save(account,connection);
//提交事务
connection.commit();
} catch (SQLException e) {
e.printStackTrace();
try {
//回滚事务
connection.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}finally {
if (connection!=null){
try {
//关闭资源
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
@Override
public Account findById(int id) {
return accountDao.findById(id);
}
@Override
public void update(Account account) {
accountDao.update(account);
}
@Override
public void del(int id) {
accountDao.del(id);
}
@Override
public void transfer(int from, int to, double money) {
//保证接下来操作 都处于同一个事物中
//事务控制基于 连接的对象
Connection connection=null;
try {
connection = dataSource.getConnection();
//修改手动提交事务
connection.setAutoCommit(false);
//偷偷将连接放入到线程中
//偷偷将连接放入到线程中
//偷偷将连接放入到线程中
//偷偷将连接放入到线程中
//偷偷将连接放入到线程中
ConnectionUtils.setConnection(connection);
accountDao.updateMoney(from,-money);
int i=5/0;
accountDao.updateMoney(to,money);
//提交事务
connection.commit();
} catch (SQLException e) {
e.printStackTrace();
try {
//回滚事务
connection.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}finally {
if (connection!=null){
try {
//关闭资源
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
package com.itheima.dao.impl;
import com.itheima.dao.AccountDao;
import com.itheima.pojo.Account;
import com.itheima.utils.ConnectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
@Repository
public class AccountDaoImpl implements AccountDao {
@Autowired
private DataSource dataSource;
@Override
public void save(Account account,Connection connection) {
System.out.println("带上数据库一起玩");
PreparedStatement preparedStatement=null;
}
@Override
public Account findById(int id) {
return new Account();
}
@Override
public void update(Account account) {
System.out.println("正在更新账户信息");
}
@Override
public void del(int id) {
System.out.println("正在根据id删除账户信息");
}
@Override
public void updateMoney(int id, double money) {
PreparedStatement preparedStatement=null;
try {
//偷偷从当前线程获取出来
//偷偷从当前线程获取出来
//偷偷从当前线程获取出来
//偷偷从当前线程获取出来
Connection connection = ConnectionUtils.getConnection();
//获取statement对象
preparedStatement = connection.prepareStatement("update account set money=money+? where id=?");
//设置参数
preparedStatement.setObject(1,money);
preparedStatement.setObject(2,id);
//执行
preparedStatement.execute();
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
//关闭资源
try {
if (preparedStatement!=null){
preparedStatement.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
通过上述改造 讲connection这个非业务对象的传递隐藏到线程中了 使程序开发者更加专注于逻辑
2.4 封装事务操作的转账逻辑
上述封装虽然将connection的传递问题解决了 但是事务控制的代码行数还是太多
决定将开启事务 提交事务 关闭事务给提取封装
2.4.1 封装MyTransactionManager
package com.itheima.transaction;
import com.itheima.utils.ConnectionUtils;
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 MyTransactionManager {
@Autowired
private DataSource dataSource;
//开启事务
public void beginTransaction() throws SQLException {
//啥叫开启事务
Connection connection = dataSource.getConnection();
//修改手动提交事务
connection.setAutoCommit(false);
//偷偷将连接放入到线程中
ConnectionUtils.setConnection(connection);
}
//提交事务
public void commit() throws SQLException {
//啥叫提交事务了
Connection connection = ConnectionUtils.getConnection();
connection.commit();
}
//回滚事务
public void rollback() {
//啥叫回滚事务
Connection connection = ConnectionUtils.getConnection();
try {
connection.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
}
public void close(){
Connection connection = ConnectionUtils.getConnection();
//将该链接从 当前线程移除
ConnectionUtils.removeConnection();
//将该链接归还给连接池
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
2.4.2 修改spring配置文件 将事务管理器对象注入spring容器中
<context:component-scan base-package="com.itheima.service,com.itheima.dao,com.itheima.transaction"></context:component-scan>
2.4.3 修改service代码 简化开发
package com.itheima.service.impl;
import com.itheima.dao.AccountDao;
import com.itheima.pojo.Account;
import com.itheima.service.AccountService;
import com.itheima.transaction.MyTransactionManager;
import com.itheima.utils.ConnectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
//注入事务管理器对象
//注入事务管理器对象
//注入事务管理器对象
//注入事务管理器对象
//注入事务管理器对象
@Autowired
private MyTransactionManager myTransactionManager;
@Override
public void save(Account account) {
System.out.println("保存操作");
}
@Override
public Account findById(int id) {
return accountDao.findById(id);
}
@Override
public void update(Account account) {
accountDao.update(account);
}
@Override
public void del(int id) {
accountDao.del(id);
}
@Override
public void transfer(int from, int to, double money) {
try {
myTransactionManager.beginTransaction();
accountDao.updateMoney(from,-money);
//int i=5/0;
accountDao.updateMoney(to,money);
//提交事务
myTransactionManager.commit();
} catch (SQLException e) {
e.printStackTrace();
myTransactionManager.rollback();
}finally {
myTransactionManager.close();
}
}
}
2.5 使用aop完成对事务逻辑增强操作
进过上述衍化过程 service控制事务代码已经很少 编写已经很方便 但是如果我们service很多业务逻辑
如果都需要使用事务控制 还是导致出现大量重复性代码
这时候我们的aop要上场了 aop特别擅长解决重复的逻辑增强操作
现在开始吧!!!
2.5.1 配置aop注解驱动
<!--开启aop的注解驱动-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
2.5.2 编写事务增强对象
package com.itheima.transaction;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* 将事务控制代码 交给我来做
*/
@Component
@Aspect
public class MyTransactionManageAdvice {
@Autowired
private MyTransactionManager myTransactionManager;
@Pointcut("execution( * com.itheima.service..*.*(..))")
public void pt(){
}
@Around("pt()")
public void around(ProceedingJoinPoint joinPoint){
//典型的环绕开始了
try {
//开启事务
myTransactionManager.beginTransaction();
//执行原来的业务代码
joinPoint.proceed();
//提交事务
myTransactionManager.commit();
}catch (Throwable e){
e.printStackTrace();
//回顾事务
myTransactionManager.rollback();
}finally {
//关闭资源
myTransactionManager.close();
}
}
}
2.5.3 修改service代码
package com.itheima.service.impl;
import com.itheima.dao.AccountDao;
import com.itheima.pojo.Account;
import com.itheima.service.AccountService;
import com.itheima.transaction.MyTransactionManager;
import com.itheima.utils.ConnectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
@Override
public void save(Account account) {
System.out.println("保存操作");
}
@Override
public Account findById(int id) {
return accountDao.findById(id);
}
@Override
public void update(Account account) {
accountDao.update(account);
}
@Override
public void del(int id) {
accountDao.del(id);
}
@Override
public void transfer(int from, int to, double money) {
//删除了大段的事务控制代码 只留下了业务代码
accountDao.updateMoney(from,-money);
int i=5/0;
accountDao.updateMoney(to,money);
}
}
最终目标我们使用了aop的切面编程 完成了对于业务层事务的控制
三、JdbcTemplate的简单使用
3.1 JdbcTemplate的简单介绍
它是 spring 框架中,spring-jdbc提供的一个对象是对原始 Jdbc API 对象的简单封装。spring 框架为我们提供了很多的操作模板类。
JdbcTemplate操作关系数据库。
3.2 JdbcTemplate的简单使用
3.2.1 导入maven依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.9</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
3.2.2 注入jdbcTemplate对象
<!--注入jdbcTemplate对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
3.2.3 使用jdbcTemplate完成增删改查
package com.itheima.dao.impl;
import com.itheima.dao.AccountDao;
import com.itheima.pojo.Account;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.List;
@Repository
public class AccountDaoImpl implements AccountDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void save(Account account) {
String sql="insert into account values(null,?,?)";
jdbcTemplate.update(sql,account.getName(),account.getMoney());
}
@Override
public Account findById(int id) {
//真是跟数据库交互的
String sql="select * from account where id=?";
//BeanPropertyRowMapper 是负责自动将结果集封装的工具
Account account = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<Account>(), id);
return account;
}
@Override
public void update(Account account) {
String sql="update account set money=? where id=?";
jdbcTemplate.update(sql,account.getMoney(),account.getId());
}
@Override
public void del(int id) {
String sql="delete from account where id=?";
jdbcTemplate.update(sql,id);
}
@Override
public void updateMoney(int id, double money) {
}
}