大数据笔记16—java基础篇12(JDBC 、连接池、事务)


苟有恒,何必三更眠五更起; 最无益,莫过一日曝十日寒 ! ! !
1数据库概述

什么是数据库

数据库数据库就是存储数据的仓库。本质是一个文件系统,数据按照特定的格式将数据存储起来,用户可以对数据库中的数据进行增加,修改,删除及查询操作。

什么是数据库管理系统

数据库管理系统(DataBase Management System,DBMS):指一种操作和管理数据库的大型软件,用于建立、使用和维护数据库,对数据库进行统一管理和控制,以保证数据库的安全性和完整性。用户通过数据库管理系统访问数据库中表内的数据。

数据库与数据库管理系统的关系
在这里插入图片描述
数据库表
数据库中以表为组织单位存储数据。
表类似我们的Java类,每个字段都有对应的数据类型。
那么用我们熟悉的java程序来与关系型数据对比,就会发现以下对应关系。
类 ------->表
类中属性 ------>表中字段
对象 ------->记录(一行记录)
表数据
根据表字段所规定的数据类型,我们可以向其中填入一条条的数据,而表中的每条数据类似类的实例对象。表中的一行一行的信息我们称之为记录。
表记录与java类对象的对应关系:
在这里插入图片描述常见数据库
常见的数据库管理系统

MYSQL:开源免费的数据库,小型的数据库.已经被Oracle收购了.MySQL6.x版本也开始收费
Oracle:收费的大型数据库,Oracle公司的产品。Oracle收购SUN公司,收购MYSQL 
DB2 :IBM公司的数据库产品,收费的。常应用在银行系统中 
SQLServer:MicroSoft 公司收费的中型的数据库。C#、.net等语言常使用 
SyBase:已经淡出历史舞台。提供了一个非常专业数据建模的工具PowerDesigner 
SQLite:嵌入式的小型数据库,应用在手机端 

常用数据库:MYSQL,Oracle

JDBC

jdbc概述

JDBC(Java DataBase Connectivity, java数据库连接)是一种用于执行SQL语句的Java API。
JDBC是Java访问数据库的标准规范,可以为不同的关系型数据库提供统一访问,它由一组用Java语言编写的接口和类组成。
JDBC需要连接驱动,驱动是两个设备要进行通信,满足一定通信数据格式,数据格式由设备提供商规定,设备提供商为设备提供驱动软件,通过软件可以与该设备进行通信。
比如说mysql的驱动包:mysql-connector-java-5.1.37-bin.jar
在这里插入图片描述
JDBC规范(掌握四个核心对象):

DriverManager:用于注册驱动
Connection: 建立与数据库的连接
Statement: 操作数据库sql语句的对象
ResultSet: 结果集或一张虚拟表

利用这四个核心对象在idea中建起连接
jdbc原理
Java提供访问数据库规范称为JDBC,而生产厂商提供规范的实现类称为驱动。
在这里插入图片描述
JDBC是接口,驱动是接口的实现,没有驱动将无法完成数据库连接,从而不能操作数据库!每个数据库厂商都需要提供自己的驱动,用来连接自己公司的数据库,也就是说驱动一般都由数据库生成厂商提供。

jdbc入门案例

准备数据
之前已学习了sql语句的使用,并创建的分类表category,今天我们将使用JDBC对分类表进行增删改查操作
这个其实就是在msql里面的命令,在之前学过的mysql指令操作如果陌生的可以参考我之前的链接稍微复习一下
链接: mysql基础操作

#创建数据库
create database itheima;
#使用数据库
use itheima;
#创建分类表
create table  category(
	cid PRIMARY KEY AUTO_INCREAMENT,
	CANME VARCHAR(100)
);
#初始化数据
insert into category (cname) values('家电');
insert into category (cname) values('服饰');
insert into category (cname) values('化妆品');

导入驱动jar包(在idea中)
创建lib目录,存放mysql的驱动mysql-connector-java-5.1.37-bin.jar
选中mysql的jar包,右键选择“Add as Library…”完成jar导入
驱动jar包

import org.junit.Test;
import java.sql.*;

public class JdbcDemo {
    /*操作步骤:
     1.注册驱动.
     2.获得连接.
     3.获得执行sql语句的对象
     4.执行sql语句,并返回结果
     5.处理结果
     6.释放资源
    */
    @Test
    public void testJdbcHelloWorld() throws ClassNotFoundException, SQLException {
 			// 注意:使用JDBC规范,采用都是 java.sql包下的内容
     	   //1. 注册驱动	
       	 Class.forName("com.mysql.jdbc.Driver");
		 //2. 获得连接
		 String url = "jdbc:mysql://127.0.0.1:3306/itheima";
		 Connection conn = DriverManager..getConnection(url,"root","itheima");
		  //3. 获得执行sql语句的对象
		  Statement stmt = conn.createStatement();
		 //4. 执行sql语句,并返回结果
		String sql = "select * from category";
		ResultSet rs = stmt.executeQuery(sql);
 //5.处理sql返回结果
        while(rs.next()){
            //获得一行数据
            int cid = rs.getInt("cid");
            String cname = rs.getString("cname");
            System.out.println(cid+" , "+cname);
        }
        //6. 释放资源
        rs.close();
        stmt.close();
        conn.close();
    }
}
console:
cid1cname家电
cid2cname服饰
cid3cname化妆品

API详解

1.注册驱动

//1. 注册驱动
Class.forName("com.mysql.jdbc.Driver");

2.获取链接
static Connection getConnection(String url, String user, String password)
参数说明:
url 需要连接数据库的位置(网址)
user 用户名
password 密码
扩展说明:

	URL:SUN公司与数据库厂商之间的一种协议 
    jdbc:mysql://localhost:3306/数据库名称
	协议:子协议:/IP:端口号 数据库 
 	mysql数据库: jdbc:mysql://localhost:3306/databaseName 
  oracle数据库: jdbc:oracle:thin:@localhost:1521:sid

3连接对象:java.sql.Connection接口
接口的实现在数据库驱动中。所有与数据库交互都是基于连接对象的
Statement createStatement() 创建操作sql语句的对象

Statement createStatement();//创建操作sql语句的对象

4. 操作sql语句:java.sql.Statement接口

String sql = "某SQL语句"; 
//获取Statement语句执行平台:
Statement stmt =con.createStatement();
//常用方法:
int executeUpdate(String sql);--执行insert update delete语句
ResultSet executeQuery(String sql); --执行select语句.
boolean execute(String sql); --仅当执行select并且有结果时才返回true,执行其他的语句返回false

5. 处理结果集 :ResultSet
注意 : 执行 insert、update、delete无需处理结果集
ResultSet实际上就是一张二维的表格,我们可以调用其boolean next()方法指向某行记录
当第一次调用next()方法时,便指向第一行记录的位置,这时就可以使用ResultSet提供的getXxx(int col)方法来获取指定列的数据:(与数组索引从0开始不同,这里索引从1开始)

rs.next();//指向第一行
rs.getInt(1);//获取第一行第一列的数据
获取数据常用方法:
Object getObject(int index) / Object getObject(String name) 获得任意对象
String getString(int index) / String getString(String name) 获得字符串
int getInt(int index) / int getInt(String name) 获得整形
double getDouble(int index) / double getDouble(String name)获得双精度浮点型

6.释放资源
与IO流一样,使用后的东西都需要关闭!关闭的顺序是先得到的后关闭,后得到的先关闭

//6. 释放资源
rs.close();
stmt.close();
conn.close();

jdbc工具类

“获得数据库连接”操作,将在以后的增删改查所有功能中都存在,可以封装为工具类:JDBCUtils。提供获取连接对象的方法,从而达到代码的重复利用。
该工具类提供方法:public static Connection getConnection()。代码如下:


public class JdbcUtils  {
    private static String driver = "com.mysql.jdbc.Driver";
    private static String url  = "jdbc:mysql://localhost:3306/itheima";
    private static String user = "root";
    private static String password = "123456";
static {
    //1,注册驱动
    try {
        Class.forName(driver);
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}
    //2,获得连接
    public static Connection getConnection() throws SQLException {
        Connection conn = DriverManager.getConnection(url, user, password);
        return conn;
    }

    //3,释放资源
    public static void closeResource(Connection conn, Statement st, ResultSet resultSet){
            if( conn != null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        if( st != null){
            try {
                st.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if( resultSet != null){
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

    }

}
**jdbc增删改查操作**
我把这四个
//插入一个值
    @Test
    public void testJdbcInsert(){
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;

        try {
            //获得连接
            connection = JdbcUtils.getConnection();
            //操作
            //1)获得语句执行者
            statement = connection.createStatement();
            //2)执行sql语句
            int r = statement.executeUpdate("insert into category(cname) values('测试')");
            //3)处理结果
            System.out.println(r);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        JdbcUtils.closeResource(connection,statement,resultSet);
    }
    //更新一个值
    @Test
    public void  testUpdate(){
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;
        try {
            //创建连接
            connection = JdbcUtils.getConnection();
            //操作
            //1)获得语句执行者
            statement= connection.createStatement();
            //2)执行sql语句
            int r = statement.executeUpdate("update category set cname='测试2' where cid = 4");
            System.out.println(r);
        } catch (SQLException e) {
            e.printStackTrace();
        }
                JdbcUtils.closeResource(connection,statement,resultSet);
    }

//删除一个值
    @Test
    public void testDelete(){
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;

        try {
            connection = JdbcUtils.getConnection();
            statement = connection.createStatement();


            int r = statement.executeUpdate("delete from category where cid = 4");
            System.out.println(r);

        } catch (SQLException e) {
            e.printStackTrace();
        }
        JdbcUtils.closeResource(connection,statement,resultSet);
    }
//查询单个信息
    @Test
    public void testJdbcQuery(){
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;

        try {
            connection = JdbcUtils.getConnection();

            statement = connection.createStatement();

            resultSet = statement.executeQuery("select * from category where cid = 2");

            if(resultSet.next()){
                String cid = resultSet.getString("cid");
                String cname = resultSet.getString("cname");
                System.out.println(cid + " @ " + cname );

            }else {
                System.out.println("这没数据啊 ");
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.closeResource(connection,statement,resultSet);
        }


    }
    //查询全部信息
    @Test
    public void testJdbcQueryAll(){
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;

        try {
            connection = JdbcUtils.getConnection();

            statement = connection.createStatement();

            resultSet = statement.executeQuery("select * from category");

            while (resultSet.next()){
                String cid = resultSet.getString("cid");
                String cname = resultSet.getString("cname");
                System.out.println(cid + " @ " + cname );

            }

        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.closeResource(connection,statement,resultSet);
        }
    }
}

预编译执行平台

1、SQL注入问题(安全问题)

SQL注入:用户输入的内容作为了SQL语句语法的一部分,改变了原有SQL真正的意义。
假设有登录SQL语句如下:

SELECT * FROM 用户表 WHERE NAME = 用户输入的用户名 AND PASSWORD = 用户输的密码;

此时,当用户输入正确的账号与密码后,查询到了信息则让用户登录。但是当用户输入的账号为XXX 密码为:XXX’ OR ‘a’=‘a’;时,则真正执行的代码变为:

SELECT * FROM 用户表 WHERE NAME = 'XXX' AND PASSWORD ='XXX' OR 'a'='a';

此时,上述查询语句时永远可以查询出结果的。那么用户就直接登录成功了,显然我们不希望看到这样的结果,这便是SQL注入问题。
为此,我们使用PreparedStatement来解决对应的问题

2API详解:预处理对象(PreparedStatement)

preparedStatement:预编译对象,是Statement对象的子类。
特点:
-性能高
-会把SQL语句先编译
-能过滤掉用户输入的关键词
1.PreparedStatement预处理对象,处理的每条sql语句中所有的实际参数,都必须使用占位符?替换

String sql ="select * from user where username = ? and password = ?";

2、设置实际参数

void setXxx(int index, Xxx xx) 将指定参数设置指定类型的值
参数1:index 实际参数序列号,从1开始。
参数2:xxx 实际参数值,xxx表示具体的类型。
例如:
setString(2, "1234") 把SQL语句中第2个位置的占位符?替换成实际参数 "1234"

3、执行SQL语句

int executeUpdate(); //执行insert update delete语句
ResultSet executeQuery(); //执行select语句
boolean execute(); //执行select返回true 执行其他的语句返回false

基于预处理实现CURD操作

//利用预处理实现插入操作 
 @Test
    public void testJdbcInsert(){
        Connection connection = null;
        PreparedStatement preparedStatement = null;


        try {
            //获得连接
            connection = JdbcUtils.getConnection();
            //处理sql语句
                String sql = "insert into category(cname) values(?)";
            //3获得预处理对象
            preparedStatement = connection.prepareStatement(sql);
            //4设置实际参数
            preparedStatement.setString(1,"预处理");
            //执行
            int r =preparedStatement.executeUpdate();
            System.out.println(r);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        JdbcUtils.closeResource(connection, preparedStatement, null);
    }


//利用预处理实现更新数据
 @Test
    public void  testUpdate(){
        Connection connection = null;
        PreparedStatement preparedStatement = null;

        try {
            //创建连接
            connection = JdbcUtils.getConnection();
            //处理sql语句
            String sql = "update category set  cname = ? where  cid = ? ";
            //2 获得预处理对象
            preparedStatement =connection.prepareStatement(sql);
            //3设置实际参数
            preparedStatement.setString(1,"测试数据");
            preparedStatement.setInt(2,3);
            int r = preparedStatement.executeUpdate();
            System.out.println(r);
        } catch (SQLException e) {
            e.printStackTrace();
        }
         JdbcUtils.closeResource(connection,PreparedStatement,resultSet);
    }

//利用预处理实现查找操作
 @Test
    public void testJdbcQuery(){
        Connection connection = null;
        PreparedStatement PreparedStatement = null;
        ResultSet resultSet = null;

        try {
            connection = JdbcUtils.getConnection();

           String sql = "select * from category where cid = ?";

            PreparedStatement = connection.prepareStatement(sql);
            PreparedStatement.setInt(1,2);
            resultSet =PreparedStatement.executeQuery();
            if(resultSet.next()){
                System.out.println("查询到");
            }else {
                System.out.println("这没数据啊 ");
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.closeResource(connection,PreparedStatement,resultSet);
        }
    }

使用连接池重写工具类

1、连接池原理
连接池理解为存放多个连接的集合。
在这里插入图片描述
使用连接池技术的目的:解决建立数据库连接耗费资源和时间很多的问题,提高性能。
2、编写标准的数据源(规范)
Java为数据库连接池提供了公共的接口:javax.sql.DataSource,各个厂商需要让自己的连接池实现这个接口。这样应用程序可以方便的切换不同厂商的连接池
常见的连接池:C3P0、DRUID

C3P0连接池

C3P0是开源免费的数据库连接池。目前使用它的开源项目有:Spring、Hibernate等。使用C3P0连接池需要导入jar包,
C3P0开发步骤:
1、idea中创建项目工程
2、在项目工作中导入jar包(数据库的驱动包、c3p0的jar包)
3、编写配置文件 c3p0-config.xml,放在src中(注:文件名一定不要写错)
4、编写工具类

 initialPoolSize : 初始连接数 刚创建好连接池的时候准备的连接数量
 maxPoolSize : 最大连接数 连接池中最多可以放多少个连接
 checkoutTimeout : 最大等待时间 连接池中没有连接时最长等待时间
 maxIdleTime : 最大空闲回收时间 连接池中的空闲连接多久没有使用就会回收
public class Dempc3p0 {
    public static void main(String[] args) {
        try {
            //创建c3p0核心类对象
            ComboPooledDataSource cpds = new ComboPooledDataSource();
            //Driver类的路径
            cpds.setDriverClass( "com.mysql.jdbc.Driver" ); //loads the jdbc driver
            //数据库路径
            cpds.setJdbcUrl( "jdbc:mysql://127.0.0.1:3306/itheima" );
            //数据库账户
            cpds.setUser("root");
            //数据库密码
            cpds.setPassword("itheima");
        } catch (PropertyVetoException e) {
            e.printStackTrace();
        }
    }
}

常用API介绍:
ComboPooledDataSource类
构造方法:

构造方法描述
ComboPooledDataSource()创建一个连接池对象,使用默认的配置参数(后面使用到配置文件再详细解释)

常用方法:

方法作用
getConnection从连接池中获得连接对象
setInitialPoolSize设置初始化连接池数量
setMaxPoolSize设置最大连接池数量
setCheckoutTimeout设置连接超时,超出时长抛出异常.

需求:从连接池中得到10个连接对象,释放其中一个,打印连接池对象查看结果
初始化连接池数量为5
最大连接池数量为10
等待2000毫秒后抛出异常

public class c3p0_Demo {
    public static void main(String[] args) {
        try {
            //创建c3p0核心类对象
            ComboPooledDataSource cpds = new ComboPooledDataSource();
            //Driver类的路径
            cpds.setDriverClass("com.mysql.jdbc.Driver");
            //数据库路径
            cpds.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/itheima");
            //数据库账户
            cpds.setUser("root");
            //数据库密码
            cpds.setPassword("itheima");
            //设置初始化连接池数量
            cpds.setInitialPoolSize(5);
            //设置最大连接池数量
            cpds.setMaxPoolSize(10);
            // 超时等待
            cpds.setCheckoutTimeout(2000);

            for (int i = 0; i < 10; i++) {
                Connection conn = cpds.getConnection();
                System.out.println("第" + i + "个连接对象:" + conn);
                if (i == 5) {
                    //注意:这里的close已经不是释放资源,而是放回到连接池中
                    conn.close();
                }
            }
                } catch (SQLException e) {
                    e.printStackTrace();
        } catch (PropertyVetoException e) {
            e.printStackTrace();
        }
    }
}

c3p0配置文件
在开发中使用C3P0通常会配置一些参数,而这些参数书写在配置文件"c3p0-config.xml"
编写配置文件:c3p0-config.xml

<?xml version='1.0' encoding='UTF-8'?> com.mysql.jdbc.Driver jdbc:mysql://127.0.0.1:3306/itheima root itheima
    <!-- 连接池参数 -->
    <property name="initialPoolSize">5</property>
    <property name="maxPoolSize">10</property>
    <property name="checkoutTimeout">2000</property>
    <property name="maxIdleTime">1000</property>
</default-config>
说明:c3p0连接池常用的配置参数说明 initialPoolSize : 初始连接数 刚创建好连接池的时候准备的连接数量 maxPoolSize : 最大连接数 连接池中最多可以放多少个连接 checkoutTimeout : 最大等待时间 连接池中没有连接时最长等待时间 maxIdleTime : 最大空闲回收时间 连接池中的空闲连接多久没有使用就会回收 **c3p0连接池工具类**
编写C3P0工具类:
import com.mchange.v2.c3p0.ComboPooledDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class JdbcUtils {
    //创建一个C3P0的连接池对象(使用c3p0-config.xml中default-config标签中对应的参数)
    public static DataSource ds = new ComboPooledDataSource();

    //从池中获得一个连接
    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }

    //释放资源
    public static void closeAll(ResultSet rs, Statement stmt, Connection conn){
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
            rs = null;
        }
        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
            stmt = null;
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
            conn = null;
        }
    }
}

C3P0连接池工具类的使用
向student表中插入1条记录
步骤:

  1. 通过数据源的工具类得到一个连接对象
  2. 创建PreparedStatement对象,书写insert语句
  3. 执行executeUpdate()方法,插入数据
  4. 释放资源
    数据表:
    create table student
    (
    id int primary key auto_increment,
    name varchar(30),
    age int ,
    score double
    );
    代码:c3p0连接池工具类的使用
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class Demo_c3p0 {
    public static void main(String[] args) throws SQLException {
        // 拿到连接
        Connection conn = JdbcUtils.getConnection();

        // 执行sql语句
        String sql = "INSERT INTO student VALUES (NULL, ?, ?, ?);";
        PreparedStatement pstmt = conn.prepareStatement(sql);
        pstmt.setString(1, "李四");
        pstmt.setInt(2, 30);
        pstmt.setDouble(3, 50);
        int i = pstmt.executeUpdate();
        System.out.println("影响的行数: " + i);

        // 关闭资源
        JdbcUtils.closeAll(null,pstmt,conn);
    }
}

事务

  • 什么是事务:指的是逻辑上得一组操作,组成这个操作得各个单元,要么全部成功,要么全部失败。
  • 作用:保证我们得sql执行过程中,不会部分成功,部分失败,维护数据得完整性
  • 举例: 张三给李四转钱, 1 张三账户扣除500, 2.;李四账户增加500。
  • 我们把事务引进来,就可以控制,若张三扣除金额成功,李四增加金额失败,张三得账户会还原成未扣除得状态。
  • 事务得关键字典说明
    • START TRANSACTION : 代表事务开始
    • COMMIT : 代表事务正常结束,所有数据正常永久得保存在数据库里
    • ROLLBACK : 代表事务中间环节失败,所有数据回滚到事务开始之前,
  • 事务特性得四大特征 : ACID
    • A 原子性(Atomicity):原子是物理中最小得单位,一个事务就是一个原子,所有得操作要么完全成功,要么完全失败。
    • C 一致性(Consistency):事务前后得数据要保持一致
    • I 隔离性(Isolation):事务与事务之间互相不干扰。
    • D 持久性(Durability):事务结束后,对数据得更新是永久性,不会再更改。

并发

  • 并发访问得问题:
    • 脏读:一个事务运行到一半,处理过的数据被另一个数据读取。
    • 不可以重复读:如果我们一个事务中读到了另一个事务更新得数据。
  • 幻读。虚读:一个事务读到了另一个事务提交得数据。
  • 如何解决并发得问题:
    • read uncommitted 读未提交 : 未解决任何并发问题
    • read committed 读已提交 :解决了脏读得问题
    • repeatable read:可重复读 : 解决了脏读,不可以重复读得问题
    • serializable 串行化 : 解决了所有问题
  • 效率来讲 read uncommitted > read committed >**repeatable read > serializable
  • 安全性: read uncommitted < read committed <**repeatable read <serializable
  • 通常用: read committed,repeatable read
  • 特殊得方向(金融银行相关)会用:serializable

Jdbc事务操作

Connection 对象的方法名描述
conn.setAutoCommit(false)开启事务
conn.commit()提交事务
conn.rollback()回滚事务

public class JdbcTransaction {
    public static void main(String[] args) {
        Connection conn = null;
        Statement stat = null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            String url = "jdbc:mysql://127.0.0.1:3306/itheima";
            conn = DriverManager.getConnection(url, "root", "123456");
            //开启事务
            conn.setAutoCommit(false);
            //3.获取执行sql语句的执行者对象Statement
            stat = conn.createStatement();
            //4.执行sql语句,获取结果
            String sql1="update account set money=money-1000 where name='jack'";
            int row1=stat.executeUpdate(sql1);
            String sql2="update account set money=money+1000 where name='rose'";
            int row2=stat.executeUpdate(sql2);
            if(row1 >0 && row2 >0){
                System.out.println("转账成功");
                conn.commit();
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("转账失败");
            try {
                conn.rollback();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        }
    }
}

表中的结果成功之后会转过去1000;

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值