Java进阶-连接池&Dbutils&事务(九)

连接池&Dbutils

在这里插入图片描述

一、连接池

在这里插入图片描述
在这里插入图片描述

1.1、连接池简述及原理

1.1.1、连接池简述及原理

在这里插入图片描述

DataSource 由连接池厂商去具体实现对应的连接池
使用连接池的目的:解决了数据库连接消耗资源和时间的很多问题,提高了性能和效率
常见的连接池有哪些?
DBCP连接池 C3P0连接池 Druid(阿里连接池)

经常用到的哪个公司的技术?

1、SUN公司(java 、 mysql) 后来被Oracle收购了
2、Oracle公司
3、Apache组织
4、阿里公司

DBCP连接池和C3P0连接池区别:

1、dbcp连接池使用效率高,但是安全性偏低
2、C3P0连接池效率偏低,但是安全性高

1.1.2、案例数据准备(步骤一)

SQL准备:

create table product(
	pid int primary key,
	pname varchar(20),
	price double
);
INSERT INTO product(pid,pname,price) VALUES(1,'联想',5000);
INSERT INTO product(pid,pname,price) VALUES(2,'海尔',3000);
INSERT INTO product(pid,pname,price) VALUES(3,'雷神',5000);
INSERT INTO product(pid,pname,price) VALUES(4,'JACK JONES',800);
INSERT INTO product(pid,pname,price) VALUES(5,'真维斯',200);
INSERT INTO product(pid,pname,price) VALUES(6,'花花公子',440);
INSERT INTO product(pid,pname,price) VALUES(7,'劲霸',2000);
INSERT INTO product(pid,pname,price) VALUES(8,'香奈儿',800);
INSERT INTO product(pid,pname,price) VALUES(9,'相宜本草',200);
INSERT INTO product(pid,pname,price) VALUES(10,'面霸',5);
INSERT INTO product(pid,pname,price) VALUES(11,'好想你枣',56);
INSERT INTO product(pid,pname,price) VALUES(12,'香飘飘奶茶',1);

1.2、DBCP连接池

1.2.1、简述

DBCP也是一个开源的连接池,是Apache Common成员之一,在企业开发中也比较常见,tomcat内置的连接池。
DBCP连接池目前市面上极为高效的连接池。
DBCP连接池一秒钟可以创建并传递10万个左右的连接对象。

DBCP安全性并不高,有可能在高速运转丢失连接数据

1.2.2、连接池使用

1.2.1.1、导入jar包(步骤二)

(点我下载对应jar包)
在这里插入图片描述

1.2.1.2、配置文件导入(步骤三)

配置文件名称: (*.properties)
在这里插入图片描述
配置文件位置:可存放任意目录,但开发建议src根目录

需求:使用连接池查询商品的名字

案例实现:
在这里插入图片描述

package com.zql;

import com.sun.org.apache.bcel.internal.generic.LoadClass;
import org.apache.commons.dbcp.BasicDataSourceFactory;

import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;

/**
 * @Author:Daniel
 * @Version 1.0
 */
public class DbcpTest {
    /*使用连接池查询商品的名字*/
    public static void main(String[] args) throws Exception {
        //创建连接池对象
        Properties pr = new Properties();
        InputStream is = DbcpTest.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
        pr.load(is);
        DataSource ds = BasicDataSourceFactory.createDataSource(pr);
        //获取连接
        Connection conn = ds.getConnection();
        String sql = "select * from product";
        PreparedStatement ps = conn.prepareStatement(sql);
        ResultSet rs = ps.executeQuery();
        while(rs.next()){
            System.out.println(rs.getString("pname"));
        }
    }
}

运行显示为:
在这里插入图片描述

1.2.1.3、编写连接池工具

(1)案例结构:
在这里插入图片描述
(2)创建连接池:

package com.zql.utils;

import org.apache.commons.dbcp.BasicDataSourceFactory;

import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

/**
 * @Author:Daniel
 * @Version 1.0
 */
public class DbcpUtils {
    public static  DataSource dataSource;
    static {
        //创建连接池
        try {
        Properties properties = new Properties();
        InputStream inputStream = DbcpUtils.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
        properties.load(inputStream);
        dataSource = BasicDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
           e.printStackTrace();
        }
    }
    //获取连接
    public static Connection getConnection(){
        try {
            return dataSource.getConnection();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}

(3)修改测试代码:
在这里插入图片描述

1.2.1.4、常见配置项(参照dbcpconfig.properties)-附录

dbcpconfig.properties

#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/dbutils
username=root
password=root
#<!-- 初始化连接 -->
initialSize=10
#最大连接数量
maxActive=50
#<!-- 最大空闲连接 -->
maxIdle=20
#<!-- 最小空闲连接 -->
minIdle=5
#<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
maxWait=60000
#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;] 
#注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。
connectionProperties=useUnicode=true;characterEncoding=gbk
#指定由连接池所创建的连接的自动提交(auto-commit)状态。
defaultAutoCommit=true
#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_UNCOMMITTED

在这里插入图片描述
参考文档

1.3、C3P0连接池

1.3.1、简述

C3P0属于开源的连接池,并且免费。目前使用它的开源框架有:Spring、Hibernate等
也属于第三方的插件,同样是不是需要导包(jar包)

1.3.2、连接池使用

1.3.2.1、导入jar包

在这里插入图片描述

1.3.2.2、配置文件引入

配置文件名称:c3p0-config.xml
配置文件位置:src

需求:使用连接池查询商品的名字

案例结构:
在这里插入图片描述
案例实现:

package com.zql.c3p0;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * @Author:Daniel
 * @Version 1.0
 */
public class C3p0Test {

    //需求:使用连接池查询商品的名字
    public static void main(String[] args) throws Exception {
        //创建连接池
        //ComboPooledDataSource cps = new ComboPooledDataSource();//未命名
        ComboPooledDataSource cps = new ComboPooledDataSource("zql");//命名 可到文件 c3p0-config.xml进行配置
        //获取连接池
        Connection connection = cps.getConnection();
        String sql  = "select * from product";
        PreparedStatement ps = connection.prepareStatement(sql);
        ResultSet rs = ps.executeQuery();
        while (rs.next()){
            System.out.println(rs.getString("pname"));
        }
    }
}
1.3.2.3、编写连接池工具—默认配置

(1)

package com.zql.utils;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import java.sql.Connection;
import java.sql.SQLException;

/**
 * @Author:Daniel
 * @Version 1.0
 */
public class C3p0Utils {
    //创建连接池
    public static ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
    //获取连接
    public static Connection getConnection() throws SQLException {
        return  comboPooledDataSource.getConnection();
    }
}

(2)修改测试代码:
在这里插入图片描述

1.3.2.4、编写连接池工具—命名配置(了解)
1.3.2.5、常见配置项-附录

在这里插入图片描述

二、DBUtils工具

2.1、DBUtils工具简述及导入

DBUtils是java编程中的数据库操作实用工具,小巧简单实用。
DBUtils封装了对JDBC的操作,简化了JDBC操作,可以少写代码。

Dbutils三个核心功能介绍

QueryRunner中提供对sql语句操作的API.(核心类 使用它调用增删改查的方法)
ResultSetHandler接口,用于定义select操作后,怎样封装结果集.
DbUtils类,它就是一个工具类,定义了关闭资源与事务处理的方法

(1)导入一系列jar包:
在这里插入图片描述
(2)创建C3P0Utils类

package com.zql.utils;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

/**
 * @Author:Daniel
 * @Version 1.0
 */
public class C3p0Utils {
    //创建连接池
    public static ComboPooledDataSource dataSource = new ComboPooledDataSource();
    public  static DataSource getDataSource() {
        return dataSource;
    }
    //获取连接
    public static Connection getConnection() throws SQLException {
        return  dataSource.getConnection();
    }
}

(4)创建Demo

package com.zql.utils;

import org.apache.commons.dbutils.QueryRunner;

/**
 * @Author:Daniel
 * @Version 1.0
 */
public class Demo {

    public static void main(String[] args) {
        //手动模式
        QueryRunner qr = new QueryRunner();
        //自动模式
        new QueryRunner(C3p0Utils.getDataSource());
    }
}

2.3、使用DBUtils核心类完成数据更新操作

QueryRunner
在这里插入图片描述
(1)引用上述 在这里插入图片描述

(2)增删改的编写:

package com.zql.utils;

import org.apache.commons.dbutils.QueryRunner;
import org.junit.jupiter.api.Test;
import java.sql.SQLException;

/**
 * @Author:Daniel
 * @Version 1.0
 */
public class Demo22 {

        @Test
        public  void addProduct() throws SQLException {
                //手动模式
            /*QueryRunner qr = new QueryRunner();
            String sql = "insert into product values(?,?,?)";
            Object [] param = {13,"Daniel",23};
            int i = qr.update(C3p0Utils.getConnection(), sql, param);
            if(i > 0){
                System.out.println("添加成功");
            }else{
                System.out.println("添加失败");
            }*/

            //自动模式
            QueryRunner qr = new QueryRunner(C3p0Utils.getDataSource());
            String sql = "insert into product values(?,?,?)";
            Object [] param = {15,"Jenny1",21};
            int add = qr.update(sql, param);
            if(add > 0){
                System.out.println("添加成功");
            }else{
                System.out.println("添加失败");
            }
        }
    //自动模式
    //修改
    @Test
    public  void updateProduct() throws SQLException {
        QueryRunner qr = new QueryRunner(C3p0Utils.getDataSource());
        String sql = "update product set pname = ? where pid = ?";
        Object [] param = {"Wendy",15};
        int add = qr.update(sql, param);
        if(add > 0){
            System.out.println("修改成功");
        }else{
            System.out.println("修改失败");
        }
    }
    //自动模式
    //删除
    @Test
    public  void deleteProduct() throws SQLException {
        QueryRunner qr = new QueryRunner(C3p0Utils.getDataSource());
        String sql = "delete from product where pid = ?";
        Object [] param = {15};
        int add = qr.update(sql, param);
        if(add > 0){
            System.out.println("删除成功");
        }else{
            System.out.println("删除失败");
        }
    }
}

2.4、使用DBUtils核心类完成数据查询操作

2.4.1、ResultSetHandler接口简介

QueryRunner
在这里插入图片描述
ResultSetHandler 结果集处理程序 ----定义好的接口
在这里插入图片描述

2.4.2、JavaBean

JavaBean是满足一个特殊格式的Java类。
作用:就是封装数据。

1、实现接口。 可序列化
2、必须有私有化属性(封装)
3、为了去向外界提供属性的操作方法,必须提供getter/setter方法
4、 必须显式创建无参构造

DBUtils工具,和其他的一些常用第三方工具,都会使用JavaBean进行数据封装。
都会反射创建JavaBean对象,一般会反射无参构造进行JavaBean的实例化创建。
注意:若没有显示创建无参构造,而创建了有参构造,那么工具反射JavaBean会报错。

2.4.3、BeanHandler

应用:根据商品id查询商品、根据用户名密码查询用户
单表查询-封装伪表的第一行数据,会把伪表的第一行数据封装到一个JavaBean中。

在这里插入图片描述

2.4.4、BeanListHandler

单表查询-封装所有查询数据

2.4.5、MapHandler

多表查询-封装整个伪表的第一条数据。封装成一个map集合 map<String,Object>
Key:字段名
Object:字段值

2.4.6、MapListHandler

在这里插入图片描述

多表查询-将整个伪表数据封装起来。 一行一个map, List

2.4.7、ScalarHandler

用于SQL语句运算返回并封装单值----Object

在这里插入图片描述
(1)创建Product类:

package com.zql.handle;

import java.io.Serializable;

/**
 * @Author:Daniel
 * @Version 1.0
 */
public class Product implements Serializable {
    private int pid;
    private String pname;
    private String price;

    public Product() {
    }

    public Product(int pid, String pname, String price) {
        this.pid = pid;
        this.pname = pname;
        this.price = price;
    }

    public int getPid() {
        return pid;
    }

    public void setPid(int pid) {
        this.pid = pid;
    }

    public String getPname() {
        return pname;
    }

    public void setPname(String pname) {
        this.pname = pname;
    }

    public String getPrice() {
        return price;
    }

    public void setPrice(String price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Product{" +
                "pid=" + pid +
                ", paname='" + pname + '\'' +
                ", price='" + price + '\'' +
                '}';
    }
}

(2)创建测试类:

package com.zql.handle;

import com.zql.utils.C3p0Utils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.*;
import org.junit.jupiter.api.Test;

import java.sql.SQLException;
import java.util.List;
import java.util.Map;

/**
 * @Author:Daniel
 * @Version 1.0
 */
public class Demo {

    //BeanHandler
    @Test
    public void selectTest1() throws SQLException {

        QueryRunner qr = new QueryRunner(C3p0Utils.getDataSource());
        String sql = "select * from product where pid = ?";
        Product pr = qr.query(sql, new BeanHandler<>(Product.class), 10);
        System.out.println(pr);
    }

    //BeanListHandler
    @Test
    public void selectTest2() throws SQLException {

        QueryRunner qr = new QueryRunner(C3p0Utils.getDataSource());
        String sql = "select * from product";
        List<Product> list = qr.query(sql, new BeanListHandler<>(Product.class));
        for (Product product:list) {
            System.out.println(product);
        }
    }

    //MapListHandler
    @Test
    public void selectTest3() throws SQLException {

        QueryRunner qr = new QueryRunner(C3p0Utils.getDataSource());
        String sql = "select * from product";
        Map<String, Object> ma = qr.query(sql, new MapHandler());
        System.out.println(ma);
    }

    //MapListHandler
    @Test
    public void selectTest4() throws SQLException {

        QueryRunner qr = new QueryRunner(C3p0Utils.getDataSource());
        String sql = "select * from product";
        List<Map<String, Object>> list = qr.query(sql, new MapListHandler());
        System.out.println(list);
    }

    // ScalarHandler
    @Test
    public void selectTest5() throws SQLException {

        QueryRunner qr = new QueryRunner(C3p0Utils.getDataSource());
        String sql = "select * from product";
        Object obj = qr.query(sql, new ScalarHandler());
        System.out.println(obj);
    }
}

三、事务

3.1 事务的应用场景说明

在实际的业务开发中,有些业务操作要多次访问数据库。一个业务要发送多条SQL语句给数据库执行。需要将多次访问数据库的操作视为一个整体来执行,要么所有的SQL语句全部执行成功。如果其中有一条SQL语句失败,就进行事务的回滚,所有的SQL语句全部执行失败。 例如: jack给tom转账,jack账号减钱,tom账号加钱

数据准备:

CREATE TABLE account (
id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(10),
balance DOUBLE
);
INSERT INTO account (NAME, balance) VALUES ('jack', 1000), (‘tom’, 1000);

模拟jack给tom转账:

3.2 操作事务

自动提交:(默认)
手动提交:

3.2.1自动提交事务

3.2.2 手动提交事务

事务有关的SQL语句:
在这里插入图片描述
手动提交事务使用步骤:
在这里插入图片描述
模拟两种场景:

3.3 事务原理

概述:事务开启之后, 所有的操作都会临时保存到事务日志, 事务日志只有在得到commit命令后才会同步到数据表中,其他任何情况都会清空事务日志(rollback,断开连接)

在这里插入图片描述

3.4 回滚点

概述:在某些成功的操作完成之后,后续的操作有可能成功有可能失败,但是不管成功还是失败,前面操作都已经成功, 可以在当前成功的位置设置一个回滚点。可以供后续失败操作返回到该位置,而不是返回所有操作,这个点称之为 回滚点。
设置回滚点语法:
savepoint 回滚点名字
回到回滚点语法:
rollback to 回滚点名字

3.5 事务的四大特性(ACID)(注意:面试高频率)

在这里插入图片描述

四、使用三层思想完成转账功能

在这里插入图片描述

4.1 没有使用事务

(1)案例数据库

CREATE TABLE account (
id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(10),
balance DOUBLE
);
INSERT INTO account (NAME, balance) VALUES ('Daniel', 1000), (‘Jenny’, 1000);

(2)案例结构
在这里插入图片描述
(3)案例实现

utils->C3p0Utils

package com.wx.utils;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import javax.sql.DataSource;

import java.sql.Connection;
import java.sql.SQLException;

/**
 * @Author:Daniel
 * @Version 1.0
 */
public class C3p0Utils {

    public static ComboPooledDataSource dataSource = new ComboPooledDataSource();

    public static  DataSource getDatasource(){
        return dataSource;
    }
    public Connection getConnection() throws SQLException {
        dataSource.getConnection();
        return null;
    }
}

domain->Account

package com.wx.domain;

import java.io.Serializable;

/**
 * @Author:Daniel
 * @Version 1.0
 */
public class Account implements Serializable {

    private int id;
    private String name;
    private double balance;

    public Account() {
    }

    public Account(int id, String name, double balance) {
        this.id = id;
        this.name = name;
        this.balance = balance;
    }

    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 getBalance() {
        return balance;
    }

    public void setBalance(double balance) {
        this.balance = balance;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", balance=" + balance +
                '}';
    }
}

web->TransferWeb

package com.wx.web;

import com.wx.service.TransferService;

import java.sql.SQLException;

/**
 * @Author:Daniel
 * @Version 1.0
 */
public class TransferWeb {
    public static void main(String[] args) {

        try {
        String fromUser = "Daniel";
        String toUser = "Jenny";
        Double money = 100.0;

        //service
        TransferService service = new TransferService();

            service.transfer(fromUser,toUser,money);
            System.out.println("转账成功");
        } catch (SQLException e) {
            System.out.println("转账失败");
            throw new RuntimeException(e);
        }
    }

}

service->TransferService

package com.wx.service;

import com.wx.dao.TransferDao;
import com.zql.zhuanzhang.TranceFer;

import java.sql.SQLException;

/**
 * @Author:Daniel
 * @Version 1.0
 */
public class TransferService {
    public void transfer(String fromUser, String toUser, Double money) throws SQLException {

        TransferDao dao = new TransferDao();

        dao.jia(money,fromUser);

        dao.jian(money,toUser);

    }
}

dao->TransferDao

package com.wx.dao;

import com.wx.utils.C3p0Utils;
import com.zql.zhuanzhang.TranceFer;
import org.apache.commons.dbutils.QueryRunner;

import java.sql.SQLException;

/**
 * @Author:Daniel
 * @Version 1.0
 */
public class TransferDao {
    public void jia(Double money, String fromUser) throws SQLException {

        QueryRunner qr = new QueryRunner(C3p0Utils.getDatasource());
        String sql = "update account set balance = balance-? where name=?";
        Object[] param={money,fromUser};
        qr.update(sql,param);
    }

    public void jian(Double money, String toUser) throws SQLException {
        QueryRunner qr = new QueryRunner(C3p0Utils.getDatasource());
        String sql="update account set balance=balance+? where name=?";
        Object[] param = {money,toUser};
        qr.update(sql,param);
    }
}

运行结果:
在这里插入图片描述

转帐前:
在这里插入图片描述

转账后:

在这里插入图片描述

4.2 使用事务

参考
建表:

CREATE TABLE account(
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(30),
money FLOAT
);

INSERT INTO account(username,money) VALUES('wency',1000),
('tom',1000),
('mary',1000);

使用到的jar包有:

c3p0-0.9.1.2.jar
commons-dbutils-1.4.jar
mysql-connector-java-5.0.8-bin.jar

c3po工具类

package com.wency.utils;
 
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
 
import javax.sql.DataSource;
 
import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.mysql.jdbc.ResultSet;
 
public class C3p0Utils {
	//创建ComboPooledDataSource对象
		private static DataSource dataSource=new ComboPooledDataSource();
		//获取连接的方法
		public static Connection getConnection(){
			try {
				return dataSource.getConnection();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				throw new RuntimeException("服务器出错");
			}
		}
		//获取数据源
		public  static DataSource getDataSource() {
			return dataSource;
		}
		//释放资源
		public static void release(Connection conn,PreparedStatement prsmt,ResultSet rs){
			if(conn!=null){
				try {
					conn.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				conn=null;
			}
			
			if(prsmt!=null){
				try {
					prsmt.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				prsmt=null;
			}
			
			if(rs!=null){
				try {
					rs.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				rs=null;
			}
			
		}
}

ThreadLocalUtil类

package com.wency.utils;
 
import java.sql.Connection;
import java.sql.SQLException;
 
public class ThreadLocalUtil {
	private static ThreadLocal<Connection> tl=new ThreadLocal<Connection>();
	
	/**
	 * 
	 * @return 从线程池中获取一个连接
	 */
	public static Connection getConnection(){
		Connection conn=tl.get();//从线程中获取连接
		//如果conn为空,则从线程池中取出 一个,如果不为空则直接返回原来那个
		//这样做的目的是为了确保事务操作时线程不被其他线程干扰
		if(conn==null){
			conn=C3p0Utils.getConnection();
			tl.set(conn);//将连接放到tl中去
		}
			return conn;
	}
	
	/**
	 * 开启事务
	 */
	public static void startTranscation(){
	    try {
			getConnection().setAutoCommit(false);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	/**
	 * 提交事务
	 */
	public static void commit(){
		try {
			getConnection().commit();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	/**
	 * 回滚事务
	 */
	public static void rollback(){
		try {
			getConnection().rollback();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	/**
	 * 释放资源
	 */
	public static void release(){
		try {
			getConnection().close();
			tl.remove();//关闭连接之后要将该线程移除
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

Account实体类

package com.wency.entity;
 
public class Account {
	private int id;
	private String username;
	float money;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public float getMoney() {
		return money;
	}
	public void setMoney(float money) {
		this.money = money;
	}
	@Override
	public String toString() {
		return "Account [id=" + id + ", username=" + username + ", money="
				+ money + "]";
	}
}

Dao接口

package com.wency.dao;
import com.wency.entity.Account;
public interface Dao {
	//修改账户操作
	 int updateAccount(String username,float money);
	//根据姓名查找账户
	 Account findAccountByName(String name);
}

Dao实现类

package com.wency.dao.impl;
 
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import com.wency.dao.Dao;
import com.wency.entity.Account;
import com.wency.utils.C3p0Utils;
 
public class DaoImpl implements Dao {
	
	private final String UPDATE="update account set money=? where username=?";
	private final String SELECT="select * from account where username=";
	
	 public DaoImpl() {
		// TODO Auto-generated constructor stub
	}
	@Override
	public  Account findAccountByName(String name) {
		// TODO Auto-generated method stub
		QueryRunner qr=new QueryRunner(C3p0Utils.getDataSource());
		List<Account> list=null;
		try {
			list = qr.query(SELECT+"'"+name+"'",new BeanListHandler<Account>(Account.class));
			return list.get(0);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
		
		}
		return null;
		
	}
 
	@Override
	public  int updateAccount(String username, float money) {
		// TODO Auto-generated method stub
		QueryRunner qr=new QueryRunner(C3p0Utils.getDataSource());
		try {
			int update = qr.update(UPDATE ,money,username);
			return update;
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			throw new RuntimeException("数据库操作异常");
		}
	}
}

Service接口

package com.wency.service;
 
 
 
public interface Service {
	void translate(float money,String fromName,String toName);
}

Service实现类

package com.wency.service.impl;
 
import com.wency.dao.Dao;
import com.wency.dao.impl.DaoImpl;
import com.wency.entity.Account;
import com.wency.service.Service;
import com.wency.utils.ThreadLocalUtil;
 
public class ServiceImpl implements Service {
 
	public void translate(float money, String username) {
		// TODO Auto-generated method stub
		
	}
	
 
	@Override
	public void translate(float money, String fromName, String toName) {
		// TODO Auto-generated method stub
		
		Dao dao=new DaoImpl();
 
		Account fromAccount=dao.findAccountByName(fromName);
		Account toAccount=dao.findAccountByName(toName);
		try {
			//开启事务
			ThreadLocalUtil.startTranscation();
			dao.updateAccount(fromName, fromAccount.getMoney()-money);
			dao.updateAccount(toName, toAccount.getMoney()+money);
			//提交事务
			ThreadLocalUtil.commit();
		} catch (Exception e) {
			// TODO: handle exception
			//如果出现异常,则回滚
			ThreadLocalUtil.rollback();
			throw new RuntimeException("操作失败");
		}finally{
			//最后将连接关闭
			ThreadLocalUtil.release();
		}
	}
}

测试类

import org.junit.Test;
 
import com.wency.dao.Dao;
import com.wency.dao.impl.DaoImpl;
import com.wency.entity.Account;
import com.wency.service.Service;
import com.wency.service.impl.ServiceImpl;
 
 
public class TestTranslate {
	@Test
	public void testTranslate(){
		Service service=new ServiceImpl();
		service.translate(500, "wency", "tom");
	}
	
	@Test
	public void testUpdate(){
		Dao dao=new DaoImpl();
		int updateAccount = dao.updateAccount("wency", 2000);
		System.out.println(updateAccount);
	}
	@Test
	public void testSelect(){
		Dao dao=new DaoImpl();
		Account account = dao.findAccountByName("wency");
		System.out.println(account);
		
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Daniel521-Spark

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值