#问题 1(100分)有一个在线交易电商平台,有两张表,分别是库存表和订单表,以下:java
如今买家XiaoMing在该平台购买bag一个,须要同时在库存表中对bag库存记录减一,同时在订单表中生成该订单的相关记录。 请编写Java程序,实现XiaoMing购买bag逻辑。订单表ID字段为自增字段,无需赋值。mysql
#解答 ##购买事务逻辑 XiaoMing购买bag一个,首先检查是否还有剩余库存,若是有库存,则进行购买,若是没有库存,返回没有库存异常。当有库存时,对库存表中的记录减一,并生成订单记录。 ##事务与锁的分析 这里必须进行加锁,否则会发生各类问题,经过查阅相关资料,肯定悲观锁,是相对稳健的形式。 ##初始化数据库 homework.sqlsql
CREATE TABLE `inventory` ( `ID` int NOT NULL AUTO_INCREMENT , `ProductName` varchar(100) NULL , `Inventory` int NULL , PRIMARY KEY (`Id`) ); INSERT INTO `inventory` (`ID`, `ProductName`, `Inventory`) VALUES ('1', 'watch', '25'); INSERT INTO `inventory` (`ID`, `ProductName`, `Inventory`) VALUES ('2', 'bag', '20'); CREATE TABLE `order` ( `ID` int NOT NULL AUTO_INCREMENT , `buyer` varchar(100) NULL , `ProductName` varchar(100) NULL , PRIMARY KEY (`Id`) );
##执行测试类数据库
package com.hava.transition; import junit.framework.TestCase; /** * Created by zhanpeng on 2016/10/8. */ public class OrderDAOTest extends TestCase { public void testTransferAccount() throws Exception { OrderDAO orderDAO = new OrderDAO(); orderDAO.init(); orderDAO.buyOne("XiaoMing","bag"); } }
##数据库访问类apache
package com.hava.transition; import org.apache.commons.dbcp2.BasicDataSource; import java.sql.*; /** * Created by zhanpeng on 2016/10/8. */ public class OrderDAO { public static BasicDataSource basicDataSource = null; public final static String JDBC_DRIVER = "com.mysql.jdbc.Driver"; public final static String DB_URL = "jdbc:mysql://192.168.1.200/test"; public final static String USER = "root"; public final static String PASSWORD = "dVHJtG0T:pf*"; public void init() { basicDataSource = new BasicDataSource(); basicDataSource.setUrl(DB_URL); basicDataSource.setDriverClassName(JDBC_DRIVER); basicDataSource.setUsername(USER); basicDataSource.setPassword(PASSWORD); } public void buyOne(String buyer,String productName) throws ClassNotFoundException { Connection connection = null; PreparedStatement preparedStatement = null; ResultSet resultSet = null; try { connection = basicDataSource.getConnection(); //开启事务 connection.setAutoCommit(false); //使用悲观锁 String getproduct_sql = "SELECT Inventory FROM inventory WHERE(ProductName = ?) FOR UPDATE"; preparedStatement = connection.prepareStatement(getproduct_sql); preparedStatement.setString(1,productName); resultSet = preparedStatement.executeQuery(); int inventory = -1; while(resultSet.next()) inventory = resultSet.getInt("Inventory"); System.out.println("[inventory]:" + inventory); if(inventory <= 0) { System.out.println("没有库存"); throw new SQLException(); } else { //减小库存 String subproduct_sql = "UPDATE inventory SET Inventory=? WHERE (ProductName = ?)"; preparedStatement = connection.prepareStatement(subproduct_sql); preparedStatement.setInt(1,inventory - 1); preparedStatement.setString(2,productName); preparedStatement.execute(); //新增订单 String addorder_sql = "INSERT INTO `order` (`buyer`, `ProductName`) VALUES (?, ?)"; preparedStatement = connection.prepareStatement(addorder_sql); preparedStatement.setString(1,buyer); preparedStatement.setString(2,productName); preparedStatement.execute(); //提交事务 connection.commit(); } } catch (SQLException e) { // ignore System.out.println("[SQLException]:" + e.toString()); //若是发生异常则回滚事务 if(connection != null) try { //发生异常回滚 connection.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } } finally { if (preparedStatement != null) { try { preparedStatement.close(); } catch (SQLException e) { e.printStackTrace(); } } if (connection != null) { try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } } } } }
#参考文献 mysql处理高并发,防止库存超卖
电商 对于特定数量的商品 如何在高并发下进行库存锁定呢?
订单系统中并发问题和锁机制的探讨
企业应用架构模式架构