我正在开发一种服务,它将接收数百万条必须插入两个表的记录。
表格
Foo
| id | name |
| 1 | foo |
酒吧
| id | name | updated | foo_id |
| 1 | bar | 0 | 1 |
实体
富
@Entity
public class Foo implements java.io.Serializable {
@Id
@GeneratedValue(strategy=IDENTITY)
private Long Id;
@Column(unique=true, nullable=false)
private String name;
@OneToMany(mappedBy="foo")
private Set<Bar> bars = new HashSet<Bar>();
// ... Constructors, gets and sets
}
酒吧
@Entity
public class Bar implements java.io.Serializable {
@Id
@GeneratedValue(strategy=IDENTITY)
private Long Id;
@Column(unique=true, nullable=false)
private String name;
@Column
private boolean updated;
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="foo_id")
private Foo foo;
// ... Constructors, gets and sets
}
这是我在的地方:
我收到一个必须插入数据库的Bar对象列表。每个Bar对象都有一个Foo关联,如果该Bar对象的Foo不在数据库中,那么它必须插入到Foo表中。此外,如果该Bar对象已经在数据库中,则必须更新它。
我的问题是我可以遇到几个并发问题,如下所示:
private session;
private transaction;
// The ModelBar and ModelFoo class have the same fields of Bar and Foo entities except it doesn't have the annotations
public void saveBars(List<ModelBar> modelBars)
{
try
{
transaction = session.beginTransaction();
session.doWork(new Work()
{
@Override
public void execute(Connection connection) throws SQLException
{
connection.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
}
});
for(ModelBar modelBar : modelBars)
{
Foo foo = getFoo(modelBar.getModelFoo().getName());
insertOrUpdateBar(modelBar, foo);
}
transaction.commit();
}
catch(Exception e)
{
// ...
}
}
private Foo getFoo(String name)
{
Foo foo = fooDAO.getFooByName(name);
if(foo == null)
{
foo = new Foo(name);
session.save(foo);
}
return foo;
}
private void insertOrUpdateBar(ModelBar modelBar, Foo foo)
{
// insert the Bar and if ConstraintViolationException is thrown then get the object from the database and update it
}
从方法 getFoo 开始。虽然起初,当我试图获得它时,我可能没有提供名称的foo,具有相同名称的foo可能被另一个服务插入。因此,当我尝试使用相同的名称保存新的Foo对象时,将抛出ConstraintViolationException,这会导致我丢失会话。
我尝试过的一个“解决方案”是:
private Foo getFoo(String name)
{
Foo foo = fooDAO.getFooByName(name);
if(foo == null)
{
Session newSession = null;
Transaction newTransaction = null;
try
{
Session newSession = getSessionFactory().openSession();
newTransaction = newSession.beginTransaction();
foo = new Foo(name);
session.save(foo);
newTransaction.commit();
}
catch (ConstraintViolationException e)
{
// rollback
foo = fooDAO.getFooByName(name);
}
finally
{
// close new session
}
}
return foo;
}
我遇到的问题是,如果在插入条形图时发生了某些事情(例如丢失的连接等),这些foo将保留在数据库中,我将无法回滚这些更改。
我遇到的另一个问题是,如果我在方法中插入条形码时使用此方法 insertOrUpdateBar 我将不得不为每个条形图创建一个新的会话,考虑到我有插入数百万的酒吧。
如果您需要有关此问题的更多详情/解释,请发表评论。