Hibernate事务和具有多个保存的会话

时间:2017-03-14 12:39:27

标签: spring hibernate session jpa transactions

谢谢,让我彻底改变它。

使用: Spring Boot,Hibernate JPA

我在所有3列中创建了一个包含复合主键的链接表(event_attendee_link_program)

我在STS IDE中使用JPA工具从我的表中生成实体,它提供了以下代码。我删除了一些列以节省空间。

EventAttendee.java

@Entity
@Table(name="event_attendee")
@NamedQuery(name="EventAttendee.findAll", query="SELECT e FROM EventAttendee e")
public class EventAttendee implements Serializable {
private static final long serialVersionUID = 1L;

@Id
@Column(name="attendee_id")
private long attendeeId;



//bi-directional many-to-one association to EventAttendeeLinkProgram
@OneToMany(mappedBy="eventAttendee")
private List<EventAttendeeLinkProgram> eventAttendeeLinkPrograms;



public List<EventAttendeeLinkProgram> getEventAttendeeLinkPrograms() {
    return this.eventAttendeeLinkPrograms;
}

public void setEventAttendeeLinkPrograms(List<EventAttendeeLinkProgram> eventAttendeeLinkPrograms) {
    this.eventAttendeeLinkPrograms = eventAttendeeLinkPrograms;
}

public EventAttendeeLinkProgram addEventAttendeeLinkProgram(EventAttendeeLinkProgram eventAttendeeLinkProgram) {
    getEventAttendeeLinkPrograms().add(eventAttendeeLinkProgram);
    eventAttendeeLinkProgram.setEventAttendee(this);

    return eventAttendeeLinkProgram;
}

public EventAttendeeLinkProgram removeEventAttendeeLinkProgram(EventAttendeeLinkProgram eventAttendeeLinkProgram) {
    getEventAttendeeLinkPrograms().remove(eventAttendeeLinkProgram);
    eventAttendeeLinkProgram.setEventAttendee(null);

    return eventAttendeeLinkProgram;
}
}

EventAttendeeLinkProgram.java

@Entity
@Table(name="event_attendee_link_program")
@NamedQuery(name="EventAttendeeLinkProgram.findAll", query="SELECT e FROM EventAttendeeLinkProgram e")
public class EventAttendeeLinkProgram implements Serializable {
private static final long serialVersionUID = 1L;

@EmbeddedId
private EventAttendeeLinkProgramPK id;

//bi-directional many-to-one association to EventAttendee
@ManyToOne
@JoinColumn(name="attendee_id", insertable=false, updatable=false)
private EventAttendee eventAttendee;

//bi-directional many-to-one association to EventOptionsAttendeeType
@ManyToOne
@JoinColumn(name="attendee_type_id", insertable=false, updatable=false)
private EventOptionsAttendeeType eventOptionsAttendeeType;

//bi-directional many-to-one association to EventProgram
@ManyToOne
@JoinColumn(name="program_id", insertable=false, updatable=false)
private EventProgram eventProgram;

public EventAttendeeLinkProgram() {
}

public EventAttendeeLinkProgramPK getId() {
    return this.id;
}

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

public EventAttendee getEventAttendee() {
    return this.eventAttendee;
}

public void setEventAttendee(EventAttendee eventAttendee) {
    this.eventAttendee = eventAttendee;
}

public EventOptionsAttendeeType getEventOptionsAttendeeType() {
    return this.eventOptionsAttendeeType;
}

public void setEventOptionsAttendeeType(EventOptionsAttendeeType eventOptionsAttendeeType) {
    this.eventOptionsAttendeeType = eventOptionsAttendeeType;
}

public EventProgram getEventProgram() {
    return this.eventProgram;
}

public void setEventProgram(EventProgram eventProgram) {
    this.eventProgram = eventProgram;
}

}

EventAttendeeLinkProgramPK.java

@Embeddable
public class EventAttendeeLinkProgramPK implements Serializable {
//default serial version id, required for serializable classes.
private static final long serialVersionUID = 1L;

@Column(name="attendee_id", insertable=false, updatable=false)
private int attendeeId;

@Column(name="attendee_type_id", insertable=false, updatable=false)
private int attendeeTypeId;

@Column(name="program_id", insertable=false, updatable=false)
private int programId;

public EventAttendeeLinkProgramPK() {
}
public int getAttendeeId() {
    return this.attendeeId;
}
public void setAttendeeId(int attendeeId) {
    this.attendeeId = attendeeId;
}
public int getAttendeeTypeId() {
    return this.attendeeTypeId;
}
public void setAttendeeTypeId(int attendeeTypeId) {
    this.attendeeTypeId = attendeeTypeId;
}
public int getProgramId() {
    return this.programId;
}
public void setProgramId(int programId) {
    this.programId = programId;
}

public boolean equals(Object other) {
    if (this == other) {
        return true;
    }
    if (!(other instanceof EventAttendeeLinkProgramPK)) {
        return false;
    }
    EventAttendeeLinkProgramPK castOther = (EventAttendeeLinkProgramPK)other;
    return 
        (this.attendeeId == castOther.attendeeId)
        && (this.attendeeTypeId == castOther.attendeeTypeId)
        && (this.programId == castOther.programId);
}

public int hashCode() {
    final int prime = 31;
    int hash = 17;
    hash = hash * prime + this.attendeeId;
    hash = hash * prime + this.attendeeTypeId;
    hash = hash * prime + this.programId;

    return hash;
}
}

EventAttendeeServiceImpl.java

@Service
@Primary
public class EventAttendeeServiceImpl implements EventAttendeeService {

@Autowired
private EventAttendeeRepository eventAttendeeRepository;

@Autowired
private EventOptionsAttendeeTypeRepository eventOptionsAttendeeTypeRepository;

@Autowired
private EventProgramRepository eventProgramRepository;

@Override
@Transactional
public String addEventAttendee(EventAttendee eventAttendee) {

        EventAttendeeLinkProgram ep = new EventAttendeeLinkProgram();
        ep.setEventOptionsAttendeeType(eventOptionsAttendeeTypeRepository.findOne(2L));
        ep.setEventProgram(eventProgramRepository.findOne(2L));

        eventAttendee.setEventAttendeeLinkPrograms(new ArrayList<>());
        eventAttendee.getEventAttendeeLinkPrograms().add(ep);

  eventAttendeeRepository.save(eventAttendee);

    return "";
}

有了这个,我的代码不会丢失任何错误。它正在保存EventAttendee,但没有任何内容保存到EventAttendeeLinkProgram。请注意:我正在尝试保存EventAttendee和EventAttendeeLinkProgram实体。所以我认为hibernate应该是聪明的,最好保存EventAttendee并为它生成Id,然后使用该Id存储在EventAttendeeLinkProgram中。

2 个答案:

答案 0 :(得分:0)

首先,用户保存直接返回标识符

SELECT v.*
FROM Vouchers AS v
  LEFT OUTER  JOIN Products AS p
    ON v.Category = p.category AND 
       ISNULL(v.Size, -1) = ISNULL(p.Size, -1) AND 
       ISNULL(v.Colour, '-1') = ISNULL(p.Colour, '-1') AND 
       ISNULL(v.Gender, '-1') = ISNULL(p.Gender, '-1')
WHERE p.ProductCode IS NULL

然后你最好在Long insertId = (Long) session.save(user); 事务本身上调用回滚,而不是从会话中再次检索事务。

最后,当使用spring时,你应该考虑让spring管理事务本身(tx使用container managed transaction)注释而不是@Transactional。这是合乎逻辑的,因为你让spring管理会话你(user managed transaction),会话和交易都应该有相同的范围(例如工作单位)。

考虑阅读有关sessionFactory.getCurrentSession()(例如JPA Session)和交易管理的一些文献。

答案 1 :(得分:0)

为什么不让春天做重物:

首先在spring中创建一个JPA存储库:

public interface UserRepository extends CrudRepository<User, Long>{
}

然后使用关系

创建2个实体
@Entity
public class User {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Long id;

    @Column(name = "name")
    private String name;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "user", orphanRemoval = true, fetch = FetchType.EAGER)
    private List<UserType> userTypes;

并且:

@Entity
public class UserType {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "user_id")
    private User user;

我的测试看起来像这样:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class UserRepositoryTest extends AbstractTest {

    @Autowired
    private UserRepository userRepository;

    @Test
    @Transactional
    public void test1() throws SQLException {
        showTables();

        User user1 = makeUser("Greg");
        userRepository.save(user1);
        System.out.println(user1);
        userRepository.save(makeUser("George"));
        assertEquals(2, userRepository.count());

        User user = userRepository.findOne(1l);
    }

    User makeUser(String name) {
        User user = new User();
        user.setName(name);
        user.setUserTypes(new ArrayList<>());
        user.getUserTypes().add(makeUserType("admin"));
        user.getUserTypes().add(makeUserType("head chef"));
        return user;
    }

    UserType makeUserType(String description) {
        UserType userType = new UserType();
        userType.setDescription(description);
        return userType;
    }
}