Java – spring hibernate persistence does not cause insertion
I'm trying to implement a simple Dao
@Repository("iUserDao") @Transactional(readOnly = true) public class UserDao implements IUserDao { private EntityManager entityManager; @PersistenceContext public void setEntityManager(EntityManager entityManager) { this.entityManager = entityManager; } @Override public User getById(int id) { return entityManager.find(User.class,id); } @Override public boolean save(User user) { entityManager.persist(user); entityManager.flush(); return true; } @Override public boolean update(User user) { entityManager.merge(user); entityManager.flush(); return true; } @Override public boolean delete(User user) { user = entityManager.getReference(User.class,user.getId()); if (user == null) return false; entityManager.remove(user); entityManager.flush(); return true; }
One entity:
@Entity @Table(name = "users") public class User { private int id; private Date creationDate; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) public int getId() { return id; } public User() { } public User(Date creationDate) { this.creationDate = creationDate; } public void setId(int id) { this.id = id; } public Date getCreationDate() { return creationDate; } public void setCreationDate(Date creationDate) { this.creationDate = creationDate; } }
This is appcontext xml: `
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerfactorybean" p:dataSource-ref="dataSource" p:jpaVendorAdapter-ref="jpaAdapter" p:persistenceUnitName="test"> <property name="loadTimeweaver"> <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeweaver"/> </property> </bean> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" p:entityManagerFactory-ref="entityManagerFactory"/> <bean id="jpaAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" p:database="MysqL" p:showsql="true"/> <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/> <tx:annotation-driven/>`
Unless I call flush () after persist () or merge (), insert will not execute. Why? If I delete @ transactional, then I encounter the error "no transaction is in progress" when refreshing, but if I delete flush, it is not inserted into the DB
Solution
It works this way because you use @ transactional (readonly = true) to mark transactions as read-only
As you can see, it won't make your transactions actually read-only, because you can still keep the changes by manually calling flush () However, it disables automatic refresh at the end of the transaction, so if there is no manual refresh, the changes will not be retained
You need to remove readonly from the class level annotation or overwrite it on a non read-only method with a method level annotation:
@Override @Transactional(readOnly = false) public boolean save(User user) { ... }
Also note that transaction partitioning is usually applied to the service layer method, not the Dao method In particular, when writing Dao methods, you actually don't know which transactions should be read-only and which are not This information is only available when designing the service layer, as shown in this example:
public class UserService { @Autowired UserDAO dao; @Transactional(readOnly = true) public User getUserById(int id) { return dao.getById(id); // getById() can participate in effectively read-only transaction } @Transactional public void changeUserName(int id,String newName) { User u = dao.getById(id); // Or not u.setName(newName); // Change will be flushed at the end of transaction } }