2017-05-04 24 views
0

我正在使用liquibase作爲我當前項目的遷移工具。爲什麼liquibase總是使用自己的序列?

問題是,我試圖使用自定義序列爲實體的自動生成ids但發生了錯誤。

我定義一個實體表和定製序列如下類似:

<databaseChangeLog> 
<changeSet id="create_orders_table" author="I am"> 
    <createTable tableName="ORDERS"> 
     <column name="id" type="SERIAL" valueComputed="SEQ_ORDERS.NEXTVAL" valueSequenceCurrent="SEQ_ORDERS.CURRENT" valueSequenceNext="SEQ_ORDERS.NEXTVAL" defaultValueSequenceNext="SEQ_ORDERS.NEXTVAL"> 
      <constraints primaryKey="true" unique="true"/> 
     </column> 
     <column name="number" type="VARCHAR(64)"/> 
     ... 
    </createTable> 
</changeSet> 
<changeSet id="add_sequence" author="I am"> 
    <createSequence sequenceName="SEQ_ORDERS" cycle="false" minValue="1" maxValue="9223372036854775807" startValue="1" incrementBy="1"/> 
</changeSet> 
</databaseChangeLog> 

但是,當被施加這種遷移我看到PostgreSQL中在下表結構:

CREATE TABLE public.orders 
(
id integer NOT NULL DEFAULT nextval('orders_id_seq'::regclass), 
"number" character varying(64), 
... 
CONSTRAINT pk_orders PRIMARY KEY (id) 
) 
WITH (
OIDS=FALSE 
); 

首先不可預知的對我來說這裏的事情是爲什麼liquibase寫了自己的orders_id_seq而不是我的SEQ_ORDERS

接下來,我寫了一個典型的JPA代碼和它的測試中使用Spring:

@Entity(name = "ORDERS") 
public class Order { 

    @Id 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ORDERS_ID_GEN") 
    @SequenceGenerator(name = "ORDERS_ID_GEN", sequenceName = "SEQ_ORDERS") 
    private long id; 

    private String number; 
    //... getters,setters and other stuff 
} 

public interface OrderRepository extends JpaRepository<Order,Long> {} 

測試

@RunWith(SpringRunner.class) 
@DataJpaTest 
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) 
@Rollback(value = false) 
public class OrderRepositoryTest { 

    @Autowired 
    private TestEntityManager testEntityManager; 

    @Autowired 
    private OrderRepository orderRepository; 


    @Test 
    public void testThatIdsOfOrdersGenerateCorrectly(){ 


     Order orderOne = new Order(); 
     orderOne.setNumber("order-n-01"); 

     Order orderTwo = new Order(); 
     orderTwo.setNumber("order-n-02"); 

     Order orderThree = new Order(); 
     orderThree.setNumber("order-n-03"); 

     testEntityManager.persist(orderOne); 
     testEntityManager.persist(orderTwo); 
     testEntityManager.persist(orderThree); 

     Assert.assertThat(orderRepository.findOne(new Long(1)),is(orderOne)); 
     Assert.assertThat(orderRepository.findOne(new Long(2)),is(orderTwo)); 
     Assert.assertThat(orderRepository.findOne(new Long(3)),is(orderThree)); 

    } 

} 

測試日誌中我看到:

Hibernate: select nextval ('seq_orders') 
... 
java.lang.AssertionError: 
Expected: is <Order(id=50, number=order-n-01, ...> 
    but: was null 

測試完成後, DB我看到三個訂單id = 50,51,52

我第一次以爲orders_id_seq每次增加值50。 我很surpised,當我測試後看到未修改orders_id_seq(當前值= 1),但我SEQ_ORDERS被遞增1

當我再次運行測試我得到了未來三年的訂單與IDS 100101102

莫非有人向我解釋這到底是怎麼回事? 和如何使液化石蠟& postgresql做正確的事情?

我使用:在PostgreSQL 9.6(org.postgresql.9.4.1212 JDBC驅動程序),Liquibase 3.5.3,春天引導1.5.2

春季啓動測試配置:

spring.jpa.hibernate.ddl-auto=none 
spring.jpa.generate-ddl=false 
spring.jpa.database=postgresql 

spring.datasource.initialize=false 
spring.datasource.username=postgres 
spring.datasource.password=******** 
spring.datasource.url=jdbc:postgresql://localhost:5432/ORDERS_TEST 
spring.datasource.driver-class-name=org.postgresql.Driver 

liquibase.change-log=classpath:/db/changelog/changelog-master.xml 

回答

1

如果您指定serial作爲數據類型,您不應指定任何默認值,因爲Postgres will already do that for you。該序列和orders_id_seq的默認值是由創建的,當您使用serial時,會自動創建PostgreSQL,它是由Liquibase創建的而不是

因此,如果您想使用自己的序列(無論出於何種原因),請指定該列爲integer,並使用nextval()指定defaultValueComputed。您還需要在創建表之前創建序列。

還爲獲得下一個值的語法是不是在Postgres的sequence.nextvalnextval('sequence')

<databaseChangeLog> 
<changeSet id="add_sequence" author="I am"> 
    <createSequence sequenceName="SEQ_ORDERS" cycle="false" minValue="1" maxValue="9223372036854775807" startValue="1" incrementBy="1"/> 
</changeSet> 

<changeSet id="create_orders_table" author="I am"> 
    <createTable tableName="ORDERS"> 
     <column name="id" type="integer" defaultValueComputed="nextval('seq_orders')> 
      <constraints primaryKey="true" unique="true"/> 
     </column> 
     <column name="number" type="VARCHAR(64)"/> 
     ... 
    </createTable> 
</changeSet> 
</databaseChangeLog> 
+0

是啊,這樣的changelog讓PostgreSQL的用我的序列,但我得到了50,51,52 IDS反正。 – rvit34

+0

@ rvit34:可能是你的模糊層中的映射有問題 - 我不使用Hibernate,所以我無法幫助你)。你可能想爲此提出一個單獨的問題(關於SO的問題應該只包含一個問題)。但這聽起來像是Hibernate中的某種緩存。或者你可能用'cache =「50」'創建序列? –

+0

正如我在PgAdmin看到的,我的SEQ_ORDERS緩存是1 – rvit34

相關問題