热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Java事务,操作数据库,实现转账

Java--事务,操作数据库,实现转账,Go语言社区,Golang程序员人脉社

更新:2019/3/29

目录

简介

事务的四个特性

一个小Demo

目录结构

jdbc.properties

JDBCUtil.java 

TestTransaction.java【核心代码】

 数据库

 demo2


简介

事务(Transaction) 其实指的一组操作,里面包含许多个单一的逻辑。只要有一个逻辑没有执行成功,那么都算失败。 所有的数据都回归到最初的状态(回滚)

简单的说:银行要把张三的钱转到李四的账户上。张三扣钱,李四加钱。这两个操作要都成功才算转账成功,不能张三扣完钱,李四没收到。事务就是解决这样的问题。

事务的四个特性

事务应该具有4个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性

原子性(atomicity)。一个事务是一个不可分割的工作单位,事务中包括的诸操作要么都做,要么都不做。

一致性(consistency)。事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。

隔离性(isolation)。一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

持久性(durability)。持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。

一个小Demo

目录结构

记得导入my-connector jar包和JUnt 5

jdbc.properties

连接数据库的配置文件

driverClass=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost/bank?useSSL=false&serverTimezOne=UTC
name=root
password=123456

要操作的是bank数据库 ,url是mysql8的写法,不然会报错

JDBCUtil.java 

工具类,直接用

package com.zhujunwei.utils;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class JDBCUtil {
	
	static String driverClass = null;
	static String url = null;
	static String name = null;
	static String password= null;
	
	static{
		try {
			//1. 创建一个属性配置对象
			Properties properties = new Properties();
//			InputStream is = new FileInputStream("jdbc.properties");
			
			
			//使用类加载器,去读取src底下的资源文件。 后面在servlet
			InputStream is = JDBCUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
			//导入输入流。
			properties.load(is);
			
			//读取属性
			driverClass = properties.getProperty("driverClass");
			url = properties.getProperty("url");
			name = properties.getProperty("name");
			password = properties.getProperty("password");
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 获取连接对象
	 * @return
	 */
	public static Connection getConn(){
		Connection cOnn= null;
		try {
			Class.forName(driverClass);
			//静态代码块 ---> 类加载了,就执行。 java.sql.DriverManager.registerDriver(new Driver());
			//DriverManager.registerDriver(new com.mysql.jdbc.Driver());
			//DriverManager.getConnection("jdbc:mysql://localhost/test?user=monty&password=greatsqldb");
			//2. 建立连接 参数一: 协议 + 访问的数据库 , 参数二: 用户名 , 参数三: 密码。
			cOnn= DriverManager.getConnection(url, name, password);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return conn;
	}
	
	/**
	 * 释放资源
	 * @param conn
	 * @param st
	 * @param rs
	 */
	public static void release(Connection conn , Statement st , ResultSet rs){
		closeRs(rs);
		closeSt(st);
		closeConn(conn);
	}
	public static void release(Connection conn , Statement st){
		closeSt(st);
		closeConn(conn);
	}

	
	private static void closeRs(ResultSet rs){
		try {
			if(rs != null){
				rs.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}finally{
			rs = null;
		}
	}
	
	private static void closeSt(Statement st){
		try {
			if(st != null){
				st.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}finally{
			st = null;
		}
	}
	
	private static void closeConn(Connection conn){
		try {
			if(conn != null){
				conn.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}finally{
			cOnn= null;
		}
	}
}

TestTransaction.java【核心代码】

package com.zhujunwei;

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

import org.junit.Test;

import com.zhujunwei.utils.JDBCUtil;

public class TestTransaction {
	@Test
	public void test() {
		
		Connection cOnn= null ;
		PreparedStatement ps = null ;
		System.out.println("-----");
		try {
			cOnn= JDBCUtil.getConn();
			//1.关闭自动提交
			conn.setAutoCommit(false);
			String sql = "update account set mOney= money- ? where id = ?";
			ps = conn.prepareStatement(sql);
			
			//减钱
			ps.setInt(1, 100);
			ps.setInt(2,1);
			int len = ps.executeUpdate();
			System.out.println("成功修改"+len+"行。");
			
                        //手工加的异常,程序要想正常运行请注释
                        int a = 10/0;
                            
			//加钱
			ps.setInt(1, -100);
			ps.setInt(2,2);
			len = ps.executeUpdate();
			System.out.println("成功修改"+len+"行。");
			
			//2.提交数据
			conn.commit();
		} catch (SQLException e) {
			//3.异常就回滚
			try {
				conn.rollback();
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
			e.printStackTrace();
		} finally {
			JDBCUtil.release(conn, ps);
		}
	}
}

 数据库

  1. 运行一波,在test()方法上鼠标右键,Run as >Junit Test

2. 你会发现程序出现错了,但是扣款是成功的,你回到数据库看一下,发现并没有变,这是因为回滚了。

把int a = 10/0;注释掉再运行一下。

3.运行是成功的,回到数据库看一下,发现数据库改变了。

 demo2

以前的老例子了,不看也罢。

package com.zjw.jdbc;

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

/**
 * 
 * @描述:事务:转账
 * @作者: zjw
 * @时间: 2018年7月19日 上午11:06:43
 */
public class TranferMain
{
	public static void main(String[] args)
	{
		String fromName = "张三1" ;
		String tOname= "李四2" ;
		double mOney= 1 ;
		
		tranfer(fromName,toName,money);
	}

	private static void tranfer(String fromName, String toName, double money)
	{
		Connection cOnnection= null ;
		PreparedStatement ps = null ;
		try
		{
			Class.forName("com.mysql.cj.jdbc.Driver");
			String url = "jdbc:mysql://localhost:3306/myfirst?useSSL=false&serverTimezOne=UTC";
			String user = "root";
			String password = "123456";
			cOnnection= DriverManager.getConnection(url, user, password);
			/* 一个链接里面的所有sql语句要么都成功,要么都失败 
			 * 
			 * 自动提交
			 * */
			boolean flag = connection.getAutoCommit();
			/* 不让自动提交
			 * mysql等数据库是自动提交的,
			 * 但是oracle:需要手动提交
			 *  */
			connection.setAutoCommit(false);
			
			String sql = "update student set balance = balance-? where name = ?";
			ps = connection.prepareStatement(sql);
			ps.setObject(1, money);
			ps.setObject(2, fromName);
			int res = ps.executeUpdate();
			if(res>0)
			{
				System.out.println(fromName+"扣钱成功"+"扣钱:"+money);
				ps.close();
				sql = "update student set balance = balance+? where name = ?"; 
				ps = connection.prepareStatement(sql);
				ps.setObject(1, money);
				ps.setObject(2, toName);
				res = ps.executeUpdate();
				if(res>0)
				{
					System.out.println(toName+"收钱成功"+"收钱:"+money);
					//提交事务
					connection.commit();
					//还原现场
					connection.setAutoCommit(flag);
				}
				
			}
			
		} catch (Exception e)
		{
			e.printStackTrace();
			//回滚
			if (connection != null)
			{
				try
				{
					connection.rollback();
				} catch (SQLException e1)
				{
					e1.printStackTrace();
				}
			}
		} finally
		{
			try
			{
				ps.close();
				ps = null ;
			} catch (SQLException e)
			{
				e.printStackTrace();
			}
			try
			{
				connection.close();
				cOnnection= null ;
			} catch (SQLException e)
			{
				e.printStackTrace();
			}
		}
	}
	
}


推荐阅读
  • 本文介绍了Swing组件的用法,重点讲解了图标接口的定义和创建方法。图标接口用来将图标与各种组件相关联,可以是简单的绘画或使用磁盘上的GIF格式图像。文章详细介绍了图标接口的属性和绘制方法,并给出了一个菱形图标的实现示例。该示例可以配置图标的尺寸、颜色和填充状态。 ... [详细]
  • phpcomposer 那个中文镜像是不是凉了 ... [详细]
  • 本文介绍了解决java开源项目apache commons email简单使用报错的方法,包括使用正确的JAR包和正确的代码配置,以及相关参数的设置。详细介绍了如何使用apache commons email发送邮件。 ... [详细]
  • 使用freemaker生成Java代码的步骤及示例代码
    本文介绍了使用freemaker这个jar包生成Java代码的步骤,通过提前编辑好的模板,可以避免写重复代码。首先需要在springboot的pom.xml文件中加入freemaker的依赖包。然后编写模板,定义要生成的Java类的属性和方法。最后编写生成代码的类,通过加载模板文件和数据模型,生成Java代码文件。本文提供了示例代码,并展示了文件目录结构。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Skywalking系列博客1安装单机版 Skywalking的快速安装方法
    本文介绍了如何快速安装单机版的Skywalking,包括下载、环境需求和端口检查等步骤。同时提供了百度盘下载地址和查询端口是否被占用的命令。 ... [详细]
  • 关键词:Golang, Cookie, 跟踪位置, net/http/cookiejar, package main, golang.org/x/net/publicsuffix, io/ioutil, log, net/http, net/http/cookiejar ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • ubuntu用sqoop将数据从hive导入mysql时,命令: ... [详细]
  • 纠正网上的错误:自定义一个类叫java.lang.System/String的方法
    本文纠正了网上关于自定义一个类叫java.lang.System/String的错误答案,并详细解释了为什么这种方法是错误的。作者指出,虽然双亲委托机制确实可以阻止自定义的System类被加载,但通过自定义一个特殊的类加载器,可以绕过双亲委托机制,达到自定义System类的目的。作者呼吁读者对网上的内容持怀疑态度,并带着问题来阅读文章。 ... [详细]
  • 本文介绍了在sqoop1.4.*版本中,如何实现自定义分隔符的方法及步骤。通过修改sqoop生成的java文件,并重新编译,可以满足实际开发中对分隔符的需求。具体步骤包括修改java文件中的一行代码,重新编译所需的hadoop包等。详细步骤和编译方法在本文中都有详细说明。 ... [详细]
  • Jboss的EJB部署描述符standardjaws.xml配置步骤详解
    本文详细介绍了Jboss的EJB部署描述符standardjaws.xml的配置步骤,包括映射CMP实体EJB、数据源连接池的获取以及数据库配置等内容。 ... [详细]
  • 本文整理了Java中java.lang.NoSuchMethodError.getMessage()方法的一些代码示例,展示了NoSuchMethodErr ... [详细]
  • maven项目_idea导入本地maven项目
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了idea导入本地maven项目相关的知识,希望对你有一定的参考价值。首先把项目关闭Fil ... [详细]
  • Question该提问来源于开源项目:react-native-device-info/react-native-device-info ... [详细]
author-avatar
mobiledu2502898533
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有