Como fazer para que 2 usuários não acessem um registro ao mesmo tempo?

No sistema que estou desenvolvendo temos uma tela para edição de roteiros. Nela precisamos garantir que apenas um usuário terá acesso àquele roteiro específico. Seria assim:

1 - se um usuário acessar um roteiro que ninguém está acessando, ele terá acesso;

2 - se um usuário acessar um roteiro que alguém está acessando, ele será avisado que o roteiro está bloqueado pelo usuário X.

3 - quando um usuário deixa de acessar o roteiro, o sistema deve deixar o roteiro disponível novamente.

PS: usamos Struts e Hibernate

Alguém já passou por uma situação parecida? Existe uma forma “consagrada” de resolver esse tipo de problema?

abraços pessoal!

:wink:

voce praticamente se respondeu,

cria uma tabela no bd com os passeios alocados e faz uma pesquisa antes de liberar.

se alguem reservar um roteiro, insira o id dele na tabela, simples assim

Imagino que você tem uma tela onde possui uma lista de todos os roteiros disponíveis, onde os usuários poderiam edita-los. Porém você quer que quando um usuário editar um determinado roteiro o mesmo seja reservado e quando um outro usuário clicar acessar o mesmo “roteiro” ele esteja em modo leitura e a mensagem informando que o roteiro está sendo editado pelo usuário.

A principio pensei que você pudesse utilizar níveis de transação do banco, mas não seria suficiente no seu caso.

Não vejo outra alternativa a não ser fazer o controle na aplicação.

Acho que a solução proposta pelo scotty, tem alguns problemas pois o que aconteceria se o usuário fechasse o browser enquanto estivesse editando o registo? E sempre que visualizasse um roteiro, seria necessário fazer uma consulta seguida de uma inserção, isso pode ser caro.

Cara acho que o lock do Hibernate pode resolver esse seu problema…
ai antes de fazer o select vc verifica se o dado esta como lock… acho que da para fazer

ou vc pode colocar um campo a mais em sua aplicação de status e toda vez que vc pegar esse dado vc altera esse campo falando que o dado esta sendo usado…

o problema disso e que toda vez que vc fizer um select vc tera que fazer um update tb

[quote=bonfarj]No sistema que estou desenvolvendo temos uma tela para edição de roteiros. Nela precisamos garantir que apenas um usuário terá acesso àquele roteiro específico. Seria assim:

1 - se um usuário acessar um roteiro que ninguém está acessando, ele terá acesso;

2 - se um usuário acessar um roteiro que alguém está acessando, ele será avisado que o roteiro está bloqueado pelo usuário X.

3 - quando um usuário deixa de acessar o roteiro, o sistema deve deixar o roteiro disponível novamente.

PS: usamos Struts e Hibernate

Alguém já passou por uma situação parecida? Existe uma forma “consagrada” de resolver esse tipo de problema?

abraços pessoal!

:wink: [/quote]

oi pessoal, valeu pelas respostas! :smiley:

eu tb pensei nessa questao de responder pelo banco, a principio parece a solucao mais simples, mas o problema é o que o oandrade levantou, e se o cara fechar a janela por exemplo? o roteiro ficaria bloqueado ate que o cara voltasse e fizesse uma modificacao. como o servidor nao recebe nenhum evento informando q o cara fechou o browser, comecei a pensar em um tempo de expiracao… sei la, uns 5 min sem acessar o roteiro. é uma boa maneira?, alguem tem sugestoes?

abracao pessoal, mais uma vez agradeco vcs!!

[quote=oandrade]Acho que a solução proposta pelo scotty, tem alguns problemas pois o que aconteceria se o usuário fechasse o browser enquanto estivesse editando o registo? E sempre que visualizasse um roteiro, seria necessário fazer uma consulta seguida de uma inserção, isso pode ser caro.
[/quote]

eu nao falei “visualizar” em lugar algum do meu post,

falei Confirmar :wink:

[quote=bonfarj]oi pessoal, valeu pelas respostas! :smiley:

eu tb pensei nessa questao de responder pelo banco, a principio parece a solucao mais simples, mas o problema é o que o oandrade levantou, e se o cara fechar a janela por exemplo? o roteiro ficaria bloqueado ate que o cara voltasse e fizesse uma modificacao. como o servidor nao recebe nenhum evento informando q o cara fechou o browser, comecei a pensar em um tempo de expiracao… sei la, uns 5 min sem acessar o roteiro. é uma boa maneira?, alguem tem sugestoes?

abracao pessoal, mais uma vez agradeco vcs!![/quote]

Havia pensado em fazer esse controle de forma assincrona, com um mdb por exemplo, mas seria necessário alterar sua arquitetura.

Você realmente precisa informar que o registro está em uso e o usuário que está utilizando-o no momento em que o roteiro é aberto para edição?

Ai eu pergunto para os mais experientes…
Não seria o caso de usar Theads, utilizando Synchronizing Code e Locks como no livro da Kathy Sierra, com exemplo de 2 pessoas não poderem debitar simultaneamente de uma mesma conta bancária :?:

[quote=oandrade]Havia pensado em fazer esse controle de forma assincrona, com um mdb por exemplo, mas seria necessário alterar sua arquitetura.

Você realmente precisa informar que o registro está em uso e o usuário que está utilizando-o no momento em que o roteiro é aberto para edição?[/quote]

preciso… mas como seria a solucao q vc ta pensando?

[quote=andersonlfl]Ai eu pergunto para os mais experientes…
Não seria o caso de usar Theads, utilizando Synchronizing Code e Locks como no livro da Kathy Sierra, com exemplo de 2 pessoas não poderem debitar simultaneamente de uma mesma conta bancária :?:[/quote]

procurei esse exemplo no google e nao achei… sabe onde posso ver isso?

valeu pessoal!

Livro: Java 2: Sun Certified Programmer & Developer for Java 2 Study Guide - Capítulo 9 - Threads

Tente aqui:

http://www.hibernate.org/hib_docs/v3/reference/en/html_single/#transactions-locking

[quote=Grinvon]Tente aqui:

http://www.hibernate.org/hib_docs/v3/reference/en/html_single/#transactions-locking[/quote]

Hibernate will always use the locking mechanism of the database, never lock objects in memory!

Você poderia utilizar o select for update, porém o usuário do banco é o mesmo para todos os usuários da aplicação, e não seria suficiente para você, pois entendo que precisa ter controle dos usuários da aplicação.

Você poderia definir que cada usuário teria um tempo X para alterar o registro reservado.

Acho que a melhor solução seria implementar um mdb para controlar o tempo da transação.

O que vocês acham ?

Você pode usar Ajax com comet para resolver o problema do usuário fechar o browser do nada.

Annotation não resolve?

Rod Jhonson, em Expert one on one - J2ee design and development utiliza um exemplo parecido. Onde você reserva assentos ao invés de roteiros.

Os controles são feitos todos na própria aplicação, desta forma o modelo fica limpo, e você evita macumbas de java script, e marteladas com Banco de dados. :lol:

Segue abaixo o código da classe ReservationRequest:

[code]package com.wrox.expertj2ee.ticket.boxoffice;

import java.io.Serializable;
import java.util.Date;

public class ReservationRequest implements Serializable {

private static final long MILLIS_PER_MINUTE = 1000L * 60L;

//-------------------------------------------------------------------------
// Instance data
//-------------------------------------------------------------------------
/** Holds value of property performanceID. */
private int performanceID;

/** Holds value of property seatsRequested. */
private int seatsRequested;

/** Holds value of property bookingFee. */
private double bookingFee;

/** Holds value of property classID. */
private int classID;

/** Holds value of property reserve. */
private boolean reserve;

private Date holdTill;

private boolean mustBeAdjacent;

//-------------------------------------------------------------------------
// Contructors
//-------------------------------------------------------------------------
/** Creates new QuoteRequest */
public ReservationRequest() {
}


/** Creates new QuoteRequest, setting all fields
 */
public ReservationRequest(int performanceID, int classID, int seatsRequested, boolean reserve, double bookingFee, int minutesToHold) throws InvalidSeatingRequestException  {
	this.performanceID = performanceID;
	this.classID = classID;
	this.seatsRequested = seatsRequested;
	this.reserve = reserve;
	this.bookingFee = bookingFee;
	holdFor(minutesToHold);
}

//-------------------------------------------------------------------------
// Bean properties
//-------------------------------------------------------------------------
/** Getter for property performanceID.
 * @return Value of property performanceID.
 */
public int getPerformanceID() {
	return performanceID;
}

/** Setter for property performanceID.
 * @param performanceID New value of property performanceID.
 */
public void setPerformanceID(int performanceID) {
	this.performanceID = performanceID;
}

/** Getter for property seatsRequested.
 * @return Value of property seatsRequested.
 */
public int getSeatsRequested() {
	return seatsRequested;
}

/** Setter for property seatsRequested.
 * @param seatsRequested New value of property seatsRequested.
 */
public void setSeatsRequested(int seatsRequested) {
	this.seatsRequested = seatsRequested;
}


public boolean getSeatsMustBeAdjacent() {
	return mustBeAdjacent;
}

public void setSeatsMustBeAdjacent(boolean mustBeAdjacent) {
	this.mustBeAdjacent = mustBeAdjacent;
}


/** Getter for property bookingFee.
 * @return Value of property bookingFee.
 */
public double getBookingFee() {
	return bookingFee;
}

/** Setter for property bookingFee.
 * @param bookingFee New value of property bookingFee.
 */
public void setBookingFee(double bookingFee) {
	this.bookingFee = bookingFee;
}

public void holdFor(int minutes) throws InvalidSeatingRequestException {
	if (holdTill != null)
		throw new InvalidSeatingRequestException("holdFor is immutable: cannot reset");
	holdTill = new Date(System.currentTimeMillis() + minutes * MILLIS_PER_MINUTE);
	
}

public Date getHoldTill() {
	//if (holdTill == null)
	//	throw new InvalidSeatingRequestException("Must set how long to hold reservation for");
	return holdTill;
}

/** Getter for property classID.
 * @return Value of property classID.
 */
public int getClassID() {
	return classID;
}

/** Setter for property classID.
 * @param classID New value of property classID.
 */
public void setClassID(int classID) {
	this.classID = classID;
}

/** Getter for property reserve.
 * @return Value of property reserve.
 */
public boolean isReserve() {
	return reserve;
}

/** Setter for property reserve.
 * @param reserve New value of property reserve.
 */
public void setReserve(boolean reserve) {
	this.reserve = reserve;
}


public String toString() {
	StringBuffer sb = new StringBuffer("Seat quote request: ");;
	sb.append("performanceID=" + performanceID + "; ");
	sb.append("classID=" + classID + "; ");
	sb.append("reserve=" + reserve + "; ");
	sb.append("held till " + holdTill + "; ");
	sb.append("seatsRequested=" + seatsRequested + "; ");
	sb.append("mustBeAdjacent=" + mustBeAdjacent + "; ");
	sb.append("bookingFee=" + bookingFee + "; ");
	return sb.toString();
}

}[/code]

http://www.wrox.com/WileyCDA/WroxTitle/productCd-0764543857,descCd-download_code.html

A solução de seus problemas estão neste livro. Boa leitura :smiley:

Abraços.