簡體   English   中英

如何在DAO設計中獲得線程安全?

[英]How to get Thread Safe in DAO design?

據我了解,使用此代碼可能會在更改用戶角色時,另一個用戶可以更改同一角色並始終贏得最后一個角色。 對於我們來說,甚至可以存儲一部分的一部分和另一部分的一部分。 由於DAO中有3個查詢,因此這是可能的。 我想獲得“ ThreadSafe”,在更改期間,其他用戶不能進行更改,否則將檢測到有人之前對其進行了更改。

我的想法是更改RoleManager中的方法。

理念:

public interface RoleManager {
static synchronized void EditRole(UserRoleBO editedObjet, UserRoleBO nonEditedObject);

這不適用於這種類型的設計(帶有接口)。

我的問題:

有沒有一種不改變設計即可解決問題的優雅方法?

補充說明:

告訴我代碼中是否有重大錯誤。

經理:

public class RoleManagerImpl implements RoleManager {

    @Override
    public void editRole(UserRoleBO editedObjet, UserRoleBO nonEditedObject) {
        EditUserRole editUserRole = EditUserRole.Factory.createEditUserRole(nonEditedObject);
        boolean hasChangedBeforeInDB = editUserRole.detectChanges();
        if (hasChangedBeforeInDB) {
            throw new ManagerException(ManagerException.TYPE.HASCHANGEDBEFOREINDB, null);
        }
        RoleDAO roleDAO = new RoleDAOImpl();
        roleDAO.editRole(editedObjet);
    }
}

DAO:

    @Override
    public int editRole(UserRoleBO role) {
        Connection conn = null;
        int status;
        try  {
            //Set up connection
            conn = ConnectionPool.getInstance().acquire();
            DSLContext create = DSL.using(conn, SQLDialect.MARIADB);

            //sql processing and return
            status = create.executeUpdate(role.getRole());
            EditUserRole editUserRole = EditUserRole.Factory.createEditUserRole(role);
            editUserRole.detectChanges();
            addPermission(editUserRole.getAddlist(), role.getRole());
            deletePermissions(editUserRole.getDeleteList(), role.getRole());        
        } 
        // Error handling sql
        catch (MappingException e) {
            throw new DAOException(DAOException.TYPE.MAPPINGEXCEPTION, e);
        } 
        catch (DataAccessException e) {
            throw new DAOException(DAOException.TYPE.DATAACCESSEXECPTION, e);
        }
        catch (Exception e) {
            throw new DAOException(DAOException.TYPE.UNKOWNEXCEPTION, e);
        } finally {
            //Connection release handling
            try{
                if(conn != null) {
                    ConnectionPool.getInstance().release(conn);
                }
            }
            // Error handling connection
            catch (DataAccessException e) {
                throw new DAOException(DAOException.TYPE.RELEASECONNECTIONEXCEPTION, e);
            }
            catch (Exception e) {
                throw new DAOException(DAOException.TYPE.UNKOWNRELEASECONNECTIONEXCEPTION, e);
            }  
        }
        //Return result
        return status;
    }

感謝您的幫助。

這只是一個可能的答案。 就我而言,我使用jooq和mariadb。

假設我們只有一個中央數據庫,則此解決方案有效。 在集群中,總是存在大腦分裂的問題。

發生的事情是我鎖定了行。 因此,如果下一個線程試圖鎖定它,則必須等待。 如果允許其繼續,則拋出異常HASCHANGEDBEFOREINDB。

請注意,您必須提交或回滾才能結束鎖定。

EditRole:

@Override
    public int editRole(UserRoleBO editedRole ,UserRoleBO nonEditedRole) throws SQLException {
        Connection conn = null;
        int status;
        try  {
            //Set up connection
            conn = ConnectionPool.getInstance().acquire();
            conn.setAutoCommit(false);
            DSLContext create = DSL.using(conn, SQLDialect.MARIADB);

            //lock rows
            lockRowsOf(editedRole, conn);


            EditUserRole editUserRole = EditUserRole.Factory.createEditUserRole(nonEditedRole);
            boolean hasChangedBeforeInDB = editUserRole.detectChanges();
            if (hasChangedBeforeInDB) {
                throw new DAOException(DAOException.TYPE.HASCHANGEDBEFOREINDB, null);
            }


            EditUserRole editUserRole2 = EditUserRole.Factory.createEditUserRole(editedRole);
            editUserRole2.detectChanges();


            //sql processing and return
            status = create.executeUpdate(editedRole.getRole());

            addPermission(editUserRole2.getAddlist(), editedRole.getRole().getId(), conn);
            deletePermissions(editUserRole2.getDeleteList(), editedRole.getRole(), conn);  
            conn.commit();
        } 
        // Error handling sql
        catch (MappingException e) {
            conn.rollback();
            throw new DAOException(DAOException.TYPE.MAPPINGEXCEPTION, e);
        } 
        catch (DataAccessException e) {
            conn.rollback();
            throw new DAOException(DAOException.TYPE.DATAACCESSEXECPTION, e);
        }
        catch (Exception e) {
            conn.rollback();
            throw new DAOException(DAOException.TYPE.UNKOWNEXCEPTION, e);
        } finally {
            //Connection release handling
            try{
                if(conn != null) {
                    conn.setAutoCommit(true);
                    ConnectionPool.getInstance().release(conn);
                }
            }
            // Error handling connection
            catch (DataAccessException e) {
                throw new DAOException(DAOException.TYPE.RELEASECONNECTIONEXCEPTION, e);
            }
            catch (Exception e) {
                throw new DAOException(DAOException.TYPE.UNKOWNRELEASECONNECTIONEXCEPTION, e);
            }  
        }
        //Return result
        return status;
    }

鎖:

 @Override
        public void lockRowsOf(UserRoleBO role, Connection conn) {
            int status;
            try  {
                DSLContext create = DSL.using(conn, SQLDialect.MARIADB);
                //sql processing and return
                status = create.select()
                        .from(AUTH_ROLE)
                        .where(AUTH_ROLE.ID.eq(role.getRole().getId()))
                        .forUpdate().execute();
                status = create.select()
                        .from(AUTH_ROLE_PERMISSION)
                        .where(AUTH_ROLE_PERMISSION.ROLE_ID.eq(role.getRole().getId()))
                        .forUpdate().execute();
            } 
            // Error handling sql
            catch (MappingException e) {
                throw new DAOException(DAOException.TYPE.MAPPINGEXCEPTION, e);
            } 
            catch (DataAccessException e) {
                throw new DAOException(DAOException.TYPE.DATAACCESSEXECPTION, e);
            }
            catch (Exception e) {
                throw new DAOException(DAOException.TYPE.UNKOWNEXCEPTION, e);
            } finally {
                //Connection will still needed to buffer the delete and insert
            }
        }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM