We ran into a major problem with our new JBoss project, where simultaneous inserts into the same table fail with unpredictable results. We're using JUnitPerf to simulate load, and it's working fine for methods that do not insert data. we're also able to manipulate records using regular unit tests with no problem.
But when we try to have 2+ threads insert into the database, we get 1 of 2 behaviors:
1) We get a null return from our web service call (instead of the new record ID), without any exception being thrown. This is not a valid return based on our code. Also:
- The first user's record shows up successfully in the database
- The ID values for the records that fail to insert are still allocated by the @Id annotation. I.e. we try to insert 1 and 2, 1 succeeds, 2 fails, but the next record is 3. This tells us that the server is creating the object, and persisting it, but it's not actually making it into the database.
java.lang.NumberFormatException: null at java.lang.Integer.parseInt(Integer.java:415) at java.lang.Integer.parseInt(Integer.java:497) at com.xrite.UserLoadTest.testAddUser(UserLoadTest.java:61) at com.clarkware.junitperf.ThreadedTest$TestRunner.run(ThreadedTest.java:75) at java.lang.Thread.run(Thread.java:595)null
2) Client-side "Parameter count mismatch" error. No errors show up in the server. This one is slightly less troubling, as it could be the result of JUnitPerf issues. Nevertheless, we cannot find any meaningful references to this error anywhere on the Web.
java.rmi.RemoteException: Parameter count mismatch: 4; nested exception is:
javax.xml.rpc.JAXRPCException: Parameter count mismatch: 4
at org.jboss.webservice.client.PortProxy.invoke(PortProxy.java:273)
at $Proxy1.updateUser(Unknown Source)
at com.xrite.UserLoadTest.testAddUser(UserLoadTest.java:61)
...
Things we have tried so far, unsuccessfully:
- Introducing a slight delay into the JUnitPerf test. In this case, everything works, but it doesn't accurately model what could happen in real life. The delay has to be at least 5 seconds between the inserts, or else the same behavior happens.
- Using various server-side synchronization approaches to prevent simulaneous inserts from happening
- Switching to PostgreSQL instead of HyperSonic for database
- Trying to specify different transaction isolation levels in hsqldb-ds.xml
- Using persistence.xml and creating entityManager from factory instead of @PersistenceContext injection
Again, we're able to do everything fine when operations are done at different times, so we're really looking for suggestions on concurrent usage, like JBoss configuration, database properties, transaction management, etc. Thanks in advance!
Alex
X-Rite
Here's some relevant code to show:
Object:
-------
@Entity
@Table(name = "Users")
public class User implements IRecord
{
private int id;
private String name = "";
@Column(name = "usId")
@Id(generate = GeneratorType.IDENTITY)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Column(name = "usName", unique = true)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
Server:
-------
@PersistenceContext
private EntityManager m_manager
public String updateUser(String sessionId, String objectXml)
{
User user = (User)m_stream.fromXML(objectXml);
IRecord record = update(user);
return Integer.toString(record.getId());
}
private IRecord update(IRecord record)
{
if (record.getId() == 0)
{
m_manager.persist(record);
return record;
}
else
{
return m_manager.merge(record);
}
}
Test:
-----
public void testAddUser() throws Throwable
{
User user = createNewNonPersistedUser(0);
String userXml = m_stream.toXML(user);
int userId = Integer.parseInt(m_endpoint.updateUser(getBackdoorSession(), userXml));
System.out.println("id: " + userId);
assertTrue(userId > 0);
}
|