數據庫開發 - 事務單元做業

#問題 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處理高併發,防止庫存超賣
電商 對於特定數量的商品 如何在高併發下進行庫存鎖定呢?
訂單系統中併發問題和鎖機制的探討
企業應用架構模式架構

相關文章
相關標籤/搜索