当数据源将事务设置为可序列化时,oneToMany 双向不起作用

发布于 2024-12-07 07:36:06 字数 4993 浏览 0 评论 0原文

我有一个使用 Spring、Struts、Hibernate 和 JPA 的应用程序。所以我有两个实体,公司和位置。 Company 与Location 是oneToMany 关系,location 与Company 是ManyToOne 关系。

位置实体:

@Entity<br>
@Table(name = "locations")<br>
@Access(AccessType.PROPERTY)<br>
public class Location implements Serializable, Comparable<Location> {

    private Company company;   

    @ManyToOne
    @JoinColumn(name="company_id")
    public Company getCompany(){
        return this.company;
    }

    public void setCompany(Company c){      
        this.company = c;
    }
}


公司实体:

@Entity
@Access(AccessType.PROPERTY)
@Table(name = "company")
public class Company implements Serializable {

    private Integer id;
    private String name;

    private List<Location> locations;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)   
    @Column(name = "id")
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    @Column(name = "name")
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @OneToMany(mappedBy="company")
    public List<Location> getLocations(){
        return this.locations;
    }

    public void setLocations(List<Location> l){
        this.locations = l;
    }

    public void addLocation(Location l){

        if (locations == null)
            locations = new ArrayList<Location>();

        if (!locations.contains(l))
                locations.add(l);

        if (l.getCompany()!=this)
            l.setCompany(this);
    }

    public void removeLocation(Location l){

        if (locations != null){             
            if (locations.contains(l))
                locations.remove(l);  
        }
    } 
}

然后当我想添加新位置时,我在 locationService 中有一个方法:

GenericService:

public abstract class GenericService {

protected Logger logger = Logger.getLogger(getClass());

@PersistenceContext(type = PersistenceContextType.EXTENDED,unitName = "MyPU")
protected EntityManager em;

public void setEntityManager(EntityManager em) {
    this.em = em;
}

public EntityManager getEntityManager() {
    return em;
}

}

位置服务:

@Transactional
public class LocationServiceImpl extends GenericService implements iLocationService {
    @Override
    public Boolean saveLocation(LocationForm lf) {

            Location l = new Location();
            Company c = companyService.getCompany(lf.getCompanyForm().getId());
            // set all location properties here from LocationForm Obj           

            l.setCompany(c);
            this.em.persist(l);         
                c.addLocation(l);
            return true;
    }
}

我必须指定作为连接池,我使用 glassfish JDBC 连接池,其中我启用了具有可重复读取级别的事务。现在一切正常,但如果从可重复读取切换到可序列化 saveLocation 方法不再起作用。
这是我使用序列化事务级别运行 saveLocation() 时的调试日志:

INFO: DEBUG [http-thread-pool-8080(5)] (SQLStatementLogger.java:111) - 
insert 
into
    locations
    (company_id, emailTransfer, liveTransfer, name, outbound_prefix, queue_id, smsTransfer, welcomeMessage) 
values
    (?, ?, ?, ?, ?, ?, ?, ?)
INFO: DEBUG [http-thread-pool-8080(5)] (SQLStatementLogger.java:111) - 
select
    locations0_.company_id as company9_153_1_,
    locations0_.id as id1_,
    locations0_.id as id146_0_,
    locations0_.company_id as company9_146_0_,
    locations0_.emailTransfer as emailTra2_146_0_,
    locations0_.liveTransfer as liveTran3_146_0_,
    locations0_.name as name146_0_,
    locations0_.outbound_prefix as outbound5_146_0_,
    locations0_.queue_id as queue6_146_0_,
    locations0_.smsTransfer as smsTrans7_146_0_,
    locations0_.welcomeMessage as welcomeM8_146_0_ 
from
    locations locations0_ 
where
    locations0_.company_id=?


然后我得到:

INFO:  WARN [http-thread-pool-8080(5)] (JDBCExceptionReporter.java:233) - SQL Error: 1205, SQLState: 41000

INFO: ERROR [http-thread-pool-8080(5)] (JDBCExceptionReporter.java:234) - Lock wait timeout exceeded; try restarting transaction

applicationContext.xml 中的某些部分

    <bean id="txManagerVA"  class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory"  ref="emfVA" />        
 </bean>
    <bean id="emfVA" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <property name="dataSource" ref="vsDS" />  
  <property name="persistenceUnitName" value="MyPU"/> 
</bean>

    <jee:jndi-lookup id="vsDS" jndi-name="jdbc/MyJndiDS"/>

<tx:annotation-driven transaction-manager="txManagerVA" />

似乎在插入之后表被锁定,没有其他表可以对其进行操作。正如我之前所说,如果我将事务隔离更改为可重复读取,一切都可以。
有人可以向我解释一下这种行为吗?

谢谢

i have a app that uses Spring,Struts, Hibernate and JPA. So i have two entities, Company and Location. Company is in oneToMany relation with Location, and location in ManyToOne to Company.

Location Entity:

@Entity<br>
@Table(name = "locations")<br>
@Access(AccessType.PROPERTY)<br>
public class Location implements Serializable, Comparable<Location> {

    private Company company;   

    @ManyToOne
    @JoinColumn(name="company_id")
    public Company getCompany(){
        return this.company;
    }

    public void setCompany(Company c){      
        this.company = c;
    }
}

Company Entity:

@Entity
@Access(AccessType.PROPERTY)
@Table(name = "company")
public class Company implements Serializable {

    private Integer id;
    private String name;

    private List<Location> locations;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)   
    @Column(name = "id")
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    @Column(name = "name")
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @OneToMany(mappedBy="company")
    public List<Location> getLocations(){
        return this.locations;
    }

    public void setLocations(List<Location> l){
        this.locations = l;
    }

    public void addLocation(Location l){

        if (locations == null)
            locations = new ArrayList<Location>();

        if (!locations.contains(l))
                locations.add(l);

        if (l.getCompany()!=this)
            l.setCompany(this);
    }

    public void removeLocation(Location l){

        if (locations != null){             
            if (locations.contains(l))
                locations.remove(l);  
        }
    } 
}

and then when i want to add a new location i have a method in locationService :

GenericService:

public abstract class GenericService {

protected Logger logger = Logger.getLogger(getClass());

@PersistenceContext(type = PersistenceContextType.EXTENDED,unitName = "MyPU")
protected EntityManager em;

public void setEntityManager(EntityManager em) {
    this.em = em;
}

public EntityManager getEntityManager() {
    return em;
}

}

Location Service:

@Transactional
public class LocationServiceImpl extends GenericService implements iLocationService {
    @Override
    public Boolean saveLocation(LocationForm lf) {

            Location l = new Location();
            Company c = companyService.getCompany(lf.getCompanyForm().getId());
            // set all location properties here from LocationForm Obj           

            l.setCompany(c);
            this.em.persist(l);         
                c.addLocation(l);
            return true;
    }
}

I have to specify that as a conection pool i use glassfish JDBC Connection Pool where i have enabled transactions with repetable read level. Everything is ok now, but if a switch from repetable read to serializable saveLocation method works no more.
This is the debug log when i run saveLocation() with serialize transaction level:

INFO: DEBUG [http-thread-pool-8080(5)] (SQLStatementLogger.java:111) - 
insert 
into
    locations
    (company_id, emailTransfer, liveTransfer, name, outbound_prefix, queue_id, smsTransfer, welcomeMessage) 
values
    (?, ?, ?, ?, ?, ?, ?, ?)
INFO: DEBUG [http-thread-pool-8080(5)] (SQLStatementLogger.java:111) - 
select
    locations0_.company_id as company9_153_1_,
    locations0_.id as id1_,
    locations0_.id as id146_0_,
    locations0_.company_id as company9_146_0_,
    locations0_.emailTransfer as emailTra2_146_0_,
    locations0_.liveTransfer as liveTran3_146_0_,
    locations0_.name as name146_0_,
    locations0_.outbound_prefix as outbound5_146_0_,
    locations0_.queue_id as queue6_146_0_,
    locations0_.smsTransfer as smsTrans7_146_0_,
    locations0_.welcomeMessage as welcomeM8_146_0_ 
from
    locations locations0_ 
where
    locations0_.company_id=?

So then i get :

INFO:  WARN [http-thread-pool-8080(5)] (JDBCExceptionReporter.java:233) - SQL Error: 1205, SQLState: 41000

INFO: ERROR [http-thread-pool-8080(5)] (JDBCExceptionReporter.java:234) - Lock wait timeout exceeded; try restarting transaction

some parts from applicationContext.xml

    <bean id="txManagerVA"  class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory"  ref="emfVA" />        
 </bean>
    <bean id="emfVA" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <property name="dataSource" ref="vsDS" />  
  <property name="persistenceUnitName" value="MyPU"/> 
</bean>

    <jee:jndi-lookup id="vsDS" jndi-name="jdbc/MyJndiDS"/>

<tx:annotation-driven transaction-manager="txManagerVA" />

It seems that after that insert the table is locked and no other operation can be performed upon it. As i said before if i change the Transaction Isolation to Repetable Read everything is ok.
Can someone explain me this behavior ?

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

雨夜星沙 2024-12-14 07:36:06

添加级联级别

 @OneToMany(mappedBy="company", cascade = CascadeType.ALL)
    public List<Location> getLocations(){
        return this.locations;
    }

然后将位置添加到公司中,并保存公司而不是位置。否则您将陷入僵局。

Add cascade level

 @OneToMany(mappedBy="company", cascade = CascadeType.ALL)
    public List<Location> getLocations(){
        return this.locations;
    }

Then add locations to company where ever and save company not the locations.You are running into a deadlock otherwise.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文