返回的键未设置 ID 字段
Posted
技术标签:
【中文标题】返回的键未设置 ID 字段【英文标题】:Id field does not set by returned key 【发布时间】:2016-01-28 23:56:14 【问题描述】:首先:生成的 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;
道
@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 日志
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)
);
【问题讨论】:
【参考方案1】:如果你使用
@GeneratedValue(strategy = GenerationType.IDENTITY)
生成的 Id 将从下一个 Id 开始,因此如果您有一行将 101 作为 id,则下一个将是 102
@GeneratedValue(strategy = GenerationType.AUTO)
将从第一个未使用的值开始。如果表中没有任何内容,他们也应该这样做。通常你应该使用 GenerationType.AUTO 来满足你的期望。
【讨论】:
仍然得到 get.id()=0 我想我需要 Identity 作为表中自动递增生成的 id?【参考方案2】:我的错。我虽然 merge(entity) 修改了传递给它的对象。解决方法是改变create方法:
public PersonalPhone create(PersonalPhone phone)
return entityManager.merge(phone);
【讨论】:
以上是关于返回的键未设置 ID 字段的主要内容,如果未能解决你的问题,请参考以下文章