不同的Hibernate save()解释

时间:2017-04-30 10:17:56

标签: spring hibernate junit hql

我制作了我的第一个Spring + Hibernate + PostgreSQL项目,并遇到了getCurrentSession().save()的hibernate解释的奇怪行为。

这是我的实体:

@Entity
@Table(name = "orders")
@Cacheable
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "order_id")
    private Long id;
    @Version
    private long version;
    @Column(name = "delivery_date")
    private Date deliveryDate;
    @Column(name = "delivery_time")
    private Time deliveryTime;
    @Column(name = "user_id")
    private Long userId;
    @Column(name = "delivery_address")
    private String deliveryAddress;
    @Column(name = "executor_id")
    private Long executorId;
    private String comment;
    @OneToMany(fetch = FetchType.EAGER, mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
    @JsonManagedReference
    private List<BasketUnit> basketUnitList = new ArrayList<>();

@Entity
@Table(name = "basket")
public class BasketUnit {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "unit_id")
    private Long id;
    @Version
    private long version;
    @Column(name = "item_id")
    private Long itemId;
    private int quantity;
    @ManyToOne
    @JsonBackReference
    @JoinColumn(name = "order_id")
    private Order order;

HibernateConfig:

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.util.Properties;


@Configuration
@EnableTransactionManagement
@PropertySource(value = {"classpath:hibernate.properties"})
public class HibernateConfig {
    private Environment environment;

    @Autowired
    HibernateConfig(Environment environment){
        this.environment = environment;
    }

    @Bean
    public LocalSessionFactoryBean sessionFactory(){
        LocalSessionFactoryBean localSessionFactoryBean = new LocalSessionFactoryBean();
        localSessionFactoryBean.setDataSource(dataSource());
        localSessionFactoryBean.setPackagesToScan("io.delivery.entity");
        localSessionFactoryBean.setHibernateProperties(hibernateProperties());
        return localSessionFactoryBean;
    }

    @Bean
    public DataSource dataSource(){
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(environment.getProperty("hibernate.driverClass"));
        dataSource.setUrl(environment.getProperty("hibernate.url"));
        dataSource.setUsername(environment.getProperty("hibernate.username"));
        dataSource.setPassword(environment.getProperty("hibernate.password"));
        return dataSource;
    }

    private Properties hibernateProperties(){
        Properties properties = new Properties();
        properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
        properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
        properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
        properties.put("hibernate.hbm2ddl.auto", environment.getRequiredProperty("hibernate.hbm2ddl.auto"));
        properties.put("show_sql", environment.getRequiredProperty("hibernate.show_sql"));
        properties.put("hibernate.cache.region.factory_class", environment.getRequiredProperty("hibernate.cache.region.factory_class"));
        return properties;
    }

    @Bean
    @Autowired
    public HibernateTransactionManager transactionManager(SessionFactory sessionFactory){
        HibernateTransactionManager transactionManager = new HibernateTransactionManager();
        transactionManager.setSessionFactory(sessionFactory);
        return transactionManager;
    }

}

DAO课程:

@Transactional
public abstract class BasicDaoImpl<T> implements BasicDao<T> {
    @Autowired
    protected SessionFactory sessionFactory;
    private Class<T> entityClass;

    public BasicDaoImpl(Class<T> entityClass) {
        this.entityClass = entityClass;
    }

    @Override
    public Session getCurrentSession() {
        return sessionFactory.getCurrentSession();
    }


    @Override
    public T create(T entity) {
        getCurrentSession().save(entity);
        return entity;
    }

我有服务的模块测试,每个测试调用create(entity)。 如果我一个接一个地运行测试,但是如果我运行测试类,我会在任何第二次测试时得到HibernateOptimisticLockingFailureException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1; nested exception is org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1

在日志中我看到Hibernate在第一次运行时在hql中解释save()

Hibernate: 
    insert 
    into
        orders
        (comment, delivery_address, delivery_date, delivery_time, executor_id, user_id, version) 
    values
        (?, ?, ?, ?, ?, ?, ?)
Hibernate: 
    insert 
    into
        basket
        (item_id, order_id, quantity, version) 
    values
        (?, ?, ?, ?)

但是对于第二次和其他运行:

Hibernate: 
    insert 
    into
        orders
        (comment, delivery_address, delivery_date, delivery_time, executor_id, user_id, version) 
    values
        (?, ?, ?, ?, ?, ?, ?)
Hibernate: 
    update
        basket 
    set
        item_id=?,
        order_id=?,
        quantity=?,
        version=? 
    where
        unit_id=? 
        and version=?

即。 update代替insert,最有可能导致错误。 这种行为可能是什么原因以及如何使save()正常工作?

或者问题可能有些不同?

更新

测试类:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {AppConfig.class, OrderServiceImpl.class, HibernateConfig.class})
public class OrderServiceTest {
    @Autowired
    private OrderService orderService;

    private static final int TEST_QUANTITY = 42;
    private static final String TEST_DELIVERY_ADDRESS = "Nowhere";
    private static final String TEST_DELIVERY_COMMENT = "Notext";

    private static List<BasketUnit> basketUnits = new ArrayList<>();

    static {
        basketUnits.add(new BasketUnit(20L));
        basketUnits.add(new BasketUnit(21L));
        basketUnits.add(new BasketUnit(22L));
        basketUnits.add(new BasketUnit(23L));
    }

    @Test
    public void updateOrder() {
        Order order = createOrder();
        assertNotNull(order);

        order.setDeliveryAddress(TEST_DELIVERY_ADDRESS);
        order.setComment(TEST_DELIVERY_COMMENT);

        Order updatedOrder = orderService.updateOrder(order);

        assertNotNull(updatedOrder);
        assertEquals(TEST_DELIVERY_ADDRESS, updatedOrder.getDeliveryAddress());
        assertEquals(TEST_DELIVERY_COMMENT, updatedOrder.getComment());
        orderService.deleteOrder(order.getId());
    }

    @Test
    public void updateBasketUnit() {

        Order order = createOrder();
        assertNotNull(order);
        assertNotNull(order.getBasketUnitList().get(0));

        order.getBasketUnitList().get(0).setQuantity(TEST_QUANTITY);
        Order updatedOrder = orderService.updateOrder(order);

        assertNotNull(updatedOrder);
        assertNotNull(updatedOrder.getId());
        assertEquals(TEST_QUANTITY, updatedOrder.getBasketUnitList().get(0).getQuantity());
        orderService.deleteOrder(order.getId());
    }

    @Test
    public void deleteBasketUnit() {

        Order order = createOrder();
        assertNotNull(order);

        List<BasketUnit> basket = order.getBasketUnitList();
        assertNotNull(basket);
        assertNotNull(basket.get(0));
        long id = basket.get(0).getId();

        orderService.deleteBasketUnitById(id);

        assertNull(orderService.findBasketUnitById(id));
        orderService.deleteOrder(order.getId());
    }

    @Test
    public void addBasketUnit() {

        Order order = createOrder();
        assertNotNull(order);

        BasketUnit basketUnitToAdd = new BasketUnit(19L);
        order.addBasketUnit(basketUnitToAdd);
        Order updatedOrder = orderService.updateOrder(order);

        assertThat(updatedOrder.getBasketUnitList(), hasItem(hasProperty("id", is(basketUnitToAdd.getId()))));
        orderService.deleteOrder(order.getId());
    }

    @Test
    public void GetByUserId() {

        Order order = createOrder();
        List<Order> ordersByUserId = orderService.findByUserId(order.getUserId());

        assertThat(ordersByUserId, hasItem(hasProperty("id", is(order.getId()))));

        assertNotNull(ordersByUserId);
        orderService.deleteOrder(order.getId());
    }

    @Test
    public void deleteOrder() {
        Order order = createOrder();
        assertNotNull(order);

        Order responceOrder = orderService.deleteOrder(order.getId());
        assertNull(orderService.findById(responceOrder.getId()));
    }

    @Test
    public void GetOrderById() {
        Order order = createOrder();

        Order responceOrder = orderService.findById(order.getId());

        assertEquals(order.getId(), responceOrder.getId());
        assertNotNull(responceOrder);
        orderService.deleteOrder(order.getId());
    }

    private Order createOrder() {
        Order order = prefillOrder();
        orderService.create(order);

        assertNotNull(order);
        return order;
    }


    private Order prefillOrder() {
        Order order = new Order();
        order.setUserId(135L);
        order.setComment("true comment");
        order.setDeliveryDate(Date.valueOf("1984-01-08"));
        order.setDeliveryTime(Time.valueOf("04:05:06"));
        order.setDeliveryAddress("Moscow");
        order.setExecutorId(350L);
        order.setBasketUnitList(basketUnits);
        return order;
    }

1 个答案:

答案 0 :(得分:0)

这种行为是由于测试中的下级表项的static状态所致,因此Hibernate在上下文中将其保留一次。