如何在DAO设计中获得线程安全?

时间:2017-06-11 22:07:43

标签: java thread-safety dao

根据我的理解,使用此代码可以在更改用户角色时,另一个用户可以更改同一个角色并始终赢得最后一个角色。我们甚至可以存储一部分和另一部分的部分。由于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;
    }

感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

这只是一个可能的答案。就我而言,我使用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
            }
        }