Id字段不由返回的密钥设置

时间:2016-01-28 23:56:15

标签: spring hibernate junit h2 transactional

首先:生成的Id不映射到实体对象。从h2日志看,似乎返回了generatedKeys结果集,并且jpa通过resultSet.getInt(1)获取密钥。但是对象id字段未设置为返回值。

第二:是否有必要使用交易?现在我正在测试简单的CRUD命令并且不需要事务,我希望提交在DAO中调用的每个方法。所以我设置autocommit = true,但是hibernate一直将它设置为false。如何解决?我希望在DAO中调用的方法连接我自己的连接和测试数据后。现在我刚创建@AfterTransactional并检查数据,但这是非常糟糕的解决方案。

模型     @实体     @Table(name =" personal_phone_tbl")     公共类PersonalPhone {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;

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

public int getId() {
    return id;
}

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

public String getNumber() {
    return number;
}

public void setNumber(String number) {
    this.number = number;
  }
}

DAO

@Repository
@Transactional
public class PersonalPhoneDao {
    @Autowired
    private EntityManager entityManager;

    public void create(PersonalPhone phone) {
        entityManager.merge(phone);
    }

context.xml中

<jee:jndi-lookup id="dataSource" jndi-name="jdbc/phonebook" expected-type="javax.sql.DataSource"/>

<bean id="entityManagerFactory"     class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceXmlLocation" value="classpath:persistence.xml"/>
    <property name="persistenceUnitName" value="phonebook-persistence"/>
    <property name="dataSource" ref="dataSource"/>
    <property name="packagesToScan" value="phonebook.*"/>
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="showSql" value="true"/>
            <property name="databasePlatform" value="org.hibernate.dialect.MySQL5Dialect"/>
        </bean>
    </property>
</bean>

<bean id="entityManager" class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>

<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

h2 Log

    INFO: Began transaction (1) for test context [DefaultTestContext@2267889d testClass = PersonalPhoneDaoTest, testInstance = com.getjavajob.web06.zhukm.PersonalPhoneDaoTest@3b3a0d10, testMethod = testInsert@AbstractDaoTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@4b06e721 testClass = PersonalPhoneDaoTest, locations = '{classpath:dao-context.xml, classpath:dao-context-overrides.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]; transaction manager [org.springframework.orm.jpa.JpaTransactionManager@602fb3d0]; rollback [false]
2016-01-29 02:48:50 jdbc[6]: 
/**/conn3.close();
2016-01-29 02:48:50 database: disconnecting session #6
2016-01-29 02:48:50 database: disconnected session #6
Hibernate: insert into personal_phone_tbl (phone) values (?)
2016-01-29 02:48:50 jdbc[4]: 
/**/conn1.prepareStatement("insert into personal_phone_tbl (phone) values (?)", 1);
2016-01-29 02:48:50 jdbc[4]: 
/**/PreparedStatement prep1 = conn1.prepareStatement("insert into personal_phone_tbl (phone) values (?)");
2016-01-29 02:48:50 jdbc[4]: 
/**/prep1.setString(1, "+7(909)6696578");
2016-01-29 02:48:50 jdbc[4]: 
/**/prep1.executeUpdate();
2016-01-29 02:48:50 lock: 1 exclusive write lock requesting for SYS
2016-01-29 02:48:50 lock: 1 exclusive write lock added for SYS
2016-01-29 02:48:50 lock: 1 exclusive write lock unlock SYS
2016-01-29 02:48:50 lock: 1 shared read lock unlock SYS
2016-01-29 02:48:50 lock: 4 shared read lock requesting for PERSONAL_PHONE_TBL
2016-01-29 02:48:50 lock: 4 shared read lock ok PERSONAL_PHONE_TBL
2016-01-29 02:48:50 jdbc[4]: 
/*SQL l:49 #:1 t:2*/insert into personal_phone_tbl (phone) values (?) {1: '+7(909)6696578'};
2016-01-29 02:48:50 jdbc[4]: 
/**/ResultSet rs21 = prep1.getGeneratedKeys();
2016-01-29 02:48:50 jdbc[4]: 
/*SQL #:1*/SELECT SCOPE_IDENTITY() WHERE SCOPE_IDENTITY() IS NOT NULL;
2016-01-29 02:48:50 jdbc[4]: 
/**/rs21.next();
2016-01-29 02:48:50 jdbc[4]: 
/**/ResultSetMetaData rsMeta0 = rs21.getMetaData();
2016-01-29 02:48:50 jdbc[4]: 
/**/conn1.getCatalog();
2016-01-29 02:48:50 jdbc[4]: 
/**/rsMeta0.getColumnCount();
2016-01-29 02:48:50 jdbc[4]: 
/**/rs21.getInt(1);
2016-01-29 02:48:50 jdbc[4]: 
/**/rs21.close();
2016-01-29 02:48:50 jdbc[4]: 
/**/prep1.getWarnings();
2016-01-29 02:48:50 jdbc[4]: 
/**/prep1.clearWarnings();
2016-01-29 02:48:50 jdbc[4]: 
/**/prep1.getMaxRows();
2016-01-29 02:48:50 jdbc[4]: 
/**/prep1.getQueryTimeout();
2016-01-29 02:48:50 jdbc[4]: 
/*SQL l:58 #:1 t:1*/SELECT VALUE FROM INFORMATION_SCHEMA.SETTINGS WHERE NAME=? {1: 'QUERY_TIMEOUT'};
2016-01-29 02:48:50 jdbc[4]: 
/**/prep1.close();
-----------------------------> personalPhone.getId()0
2016-01-29 02:48:50 jdbc[4]: 
/**/conn1.commit();
2016-01-29 02:48:50 lock: 4 shared read lock unlock PERSONAL_PHONE_TBL
2016-01-29 02:48:50 jdbc[4]: 
/*SQL */COMMIT;
2016-01-29 02:48:50 jdbc[4]: 
/**/conn1.setAutoCommit(true);
2016-01-29 02:48:50 jdbc[4]: 
/**/conn1.commit();
2016-01-29 02:48:50 jdbc[4]: 
/*SQL */COMMIT;
2016-01-29 02:48:50 jdbc[4]: 
/**/conn1.isClosed();
2016-01-29 02:48:50 jdbc[4]: 
/**/conn1.getWarnings();
2016-01-29 02:48:50 jdbc[4]: 
/**/conn1.clearWarnings();
2016-01-29 02:48:50 jdbc[4]: 
/**/conn1.isClosed();
2016-01-29 02:48:50 jdbc[4]: 
/**/conn1.clearWarnings();
Jan 29, 2016 2:48:50 AM org.springframework.test.context.transaction.TransactionContext endTransaction
INFO: Committed transaction for test context [DefaultTestContext@2267889d testClass = PersonalPhoneDaoTest, testInstance = com.getjavajob.web06.zhukm.PersonalPhoneDaoTest@3b3a0d10, testMethod = testInsert@AbstractDaoTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@4b06e721 testClass = PersonalPhoneDaoTest, locations = '{classpath:dao-context.xml, classpath:dao-context-overrides.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]].
-----------------------------> @AfterTransaction
-----------------------------> personalPhone.getId()0
2016-01-29 02:48:50 database: connecting session #7 to mem:test
2016-01-29 02:48:50 jdbc[7]: 
/*SQL */SET MODE MYSQL;
2016-01-29 02:48:50 jdbc[7]: 
/*SQL */SET DB_CLOSE_DELAY -1;
2016-01-29 02:48:50 jdbc[7]: 
/**/Connection conn4 = DriverManager.getConnection("jdbc:h2:mem:test;MODE=MYSQL;DB_CLOSE_DELAY=-1", "SA", "");
2016-01-29 02:48:50 jdbc[7]: 
/**/conn4.setAutoCommit(false);
2016-01-29 02:48:50 jdbc[7]: 
/**/Statement stat2 = conn4.createStatement();
2016-01-29 02:48:50 jdbc[7]: 
/**/ResultSet rs22 = stat2.executeQuery("SELECT * FROM personal_phone_tbl");
2016-01-29 02:48:50 jdbc[7]: 
/*SQL #:1*/SELECT * FROM personal_phone_tbl;
2016-01-29 02:48:50 jdbc[7]: 
/**/rs22.next();
----------------------------->ResultSet
2016-01-29 02:48:50 jdbc[7]: 
   /**/rs22.getObject(1);
1
2016-01-29 02:48:50 jdbc[7]: 
/**/rs22.getObject(2);
+7(909)6696578
----------------------------->ResultSet
2016-01-29 02:48:50 jdbc[7]: 
/**/stat2.close();
2016-01-29 02:48:50 jdbc[7]: 
/**/conn4.close();
2016-01-29 02:48:50 database: disconnecting session #7
2016-01-29 02:48:50 database: disconnected session #7
2016-01-29 02:48:50 database: closing mem:test from shutdown hook
2016-01-29 02:48:50 database: disconnecting session #4
2016-01-29 02:48:50 database: closing mem:test
2016-01-29 02:48:50 lock: 1 exclusive write lock requesting for SYS
2016-01-29 02:48:50 lock: 1 exclusive write lock added for SYS
2016-01-29 02:48:50 lock: 1 exclusive write lock unlock SYS
2016-01-29 02:48:50 lock: 1 shared read lock unlock SYS
2016-01-29 02:48:50 database: closed

测试

@Before
public void createDb() {
    super.dropTables();
    super.createDb();
    personalPhone = new PersonalPhone();
    personalPhone.setNumber("123456");
}

@Override
public void testInsert() {
    personalPhoneDao.create(personalPhone);
    System.out.println("-----------------------------> personalPhone.getId()"+personalPhone.getId());
    connect();
    try (Statement statement = connection.createStatement()) {
        ResultSet resultSet = statement.executeQuery(SELECT);
        if(resultSet.next()){
            System.out.println("----------------------------->ResultSet");
            System.out.println(resultSet.getObject(1));
            System.out.println(resultSet.getInt("id"));
            System.out.println(resultSet.getObject(2));
            System.out.println("----------------------------->ResultSet");
        } else {
            Assert.fail();
        }
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        super.close();
    }
}

CREATE TABLE personal_phone_tbl(
id INT NOT NULL AUTO_INCREMENT,
phone VARCHAR(25) NOT NULL,
employee_id INT,
PRIMARY KEY(id),
FOREIGN KEY (employee_id) REFERENCES employee_tbl(id)
);

2 个答案:

答案 0 :(得分:0)

如果您使用

@GeneratedValue(strategy = GenerationType.IDENTITY)

生成的Id将从下一个Id开始,所以如果你有一行将101作为id,那么下一个将是102

@GeneratedValue(strategy = GenerationType.AUTO)

将从第一个未使用的值开始。如果表中没有任何内容,他们也应该这样做。通常你应该使用符合预期的GenerationType.AUTO。

答案 1 :(得分:0)

我的坏。我虽然merge(实体)修改了传递给它的对象。解决方案是更改create方法:

 public PersonalPhone create(PersonalPhone phone) {
        return entityManager.merge(phone);
    }