我是Spring世界的新手,我开发了一个使用Spring 3.2.1和Hibernate 4.1.9来实现DAO的简单项目。该项目工作正常,但我对使用 @Transactional Spring注释对此DAO的CRUD方法有疑问。
这是实现项目的CRUD操作的类的完整代码:
package org.andrea.myexample.HibernateOnSpring.dao;
import java.util.List;
import org.andrea.myexample.HibernateOnSpring.entity.Person;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.springframework.transaction.annotation.Transactional;
public class PersonDAOImpl implements PersonDAO {
// Factory per la creazione delle sessioni di Hibernate:
private static SessionFactory sessionFactory;
// Metodo Setter per l'iniezione della dipendenza della SessionFactory:
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
/** CREATE CRUD Operation:
* Aggiunge un nuovo record rappresentato nella tabella rappresentato
* da un oggetto Person
*/
@Transactional(readOnly = false)
public Integer addPerson(Person p) {
System.out.println("Inside addPerson()");
Session session = sessionFactory.openSession();
Transaction tx = null;
Integer personID = null;
try {
tx = session.beginTransaction();
personID = (Integer) session.save(p);
tx.commit();
} catch (HibernateException e) {
if (tx != null)
tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
return personID;
}
// READ CRUD Operation (legge un singolo record avente uno specifico id):
public Person getById(int id) {
System.out.println("Inside getById()");
Session session = sessionFactory.openSession();
Transaction tx = null;
Person retrievedPerson = null;
try {
tx = session.beginTransaction();
retrievedPerson = (Person) session.get(Person.class, id);
tx.commit();
}catch (HibernateException e) {
if (tx != null)
tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
return retrievedPerson;
}
// READ CRUD Operation (recupera la lista di tutti i record nella tabella):
@SuppressWarnings("unchecked")
public List<Person> getPersonsList() {
System.out.println("Inside getPersonsList()");
Session session = sessionFactory.openSession();
Transaction tx = null;
List<Person> personList = null;
try {
tx = session.beginTransaction();
Criteria criteria = session.createCriteria(Person.class);
personList = criteria.list();
System.out.println("personList: " + personList);
tx.commit();
}catch (HibernateException e) {
if (tx != null)
tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
return personList;
}
// DELETE CRUD Operation (elimina un singolo record avente uno specifico id):
public void delete(int id) {
System.out.println("Inside delete()");
Session session = sessionFactory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
Person personToDelete = getById(id);
session.delete(personToDelete);
tx.commit();
}catch (HibernateException e) {
if (tx != null)
tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
@Transactional
public void update(Person personToUpdate) {
System.out.println("Inside update()");
Session session = sessionFactory.openSession();
Transaction tx = null;
try {
System.out.println("Insite update() method try");
tx = session.beginTransaction();
session.update(personToUpdate);
tx.commit();
}catch (HibernateException e) {
if (tx != null)
tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
}
好的,你可以看到一些方法是使用@Transactional注释注释的。
我在这里阅读官方文档http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/transaction.html,关于在方法上使用此注释,它看到:使用@Transactional注释的方法必须具有事务语义,但它意味着什么事务语义?
这意味着必须将执行方法视为执行事务?因此,这意味着必须将方法操作视为可能导致成功或失败的单个操作,如果成功,操作结果必须是永久性的,而如果未能返回到之前的状态,则交易的开始。
这是在方法上使用 @Transactional 注释的含义吗?
addPerson()方法的@Transactional注释中 readOnly = false 属性的确切含义是什么?这意味着我还可以在数据库中写一条记录(而不仅仅是读取它)还是什么?怀疑是相关的,因为我已经明白,默认情况下,使用@Transactional注释定义的交易是读/写而不只是阅读...... 我还尝试删除(readOnly = false)属性并且仍能正常工作(在数据库表中插入新记录)
下面的dout是:“为什么某些方法使用@Transactional注释和其他一些方法没有注释?用@Transactional来表示所有CRUD方法是一个很好的实践吗?”
TNX
安德烈
答案 0 :(得分:69)
首先,你不应该使DAO方法成为事务性的,而是服务方法。
其次,使用Transactional是一种让Spring为您启动和提交/回滚事务的方法。所以你不应该自己启动和提交交易。
第三:只有当你使用知道如何将Hibernate会话与事务关联的事务管理器(通常是HibernateTransactionManager
)时,这才有效。会话工厂也应该由Spring处理,并由Spring在你的DAO中注入。 DAO的代码应如下所示:
第四:你不应该打开一个新的会话,而是获得当前的会话,与春天的当前交易相关联。
public class PersonDAOImpl implements PersonDAO {
@Autowired
private SessionFactory sessionFactory;
public Integer addPerson(Person p) {
Session session = sessionFactory.getCurrentSession();
Integer personID = (Integer) session.save(p);
return personID;
}
public Person getById(int id) {
Session session = sessionFactory.getCurrentSession();
Person retrievedPerson = (Person) session.get(Person.class, id);
return retrievedPerson;
}
@SuppressWarnings("unchecked")
public List<Person> getPersonsList() {
Session session = sessionFactory.getCurrentSession();
Criteria criteria = session.createCriteria(Person.class);
return criteria.list();
}
public void delete(int id) {
Session session = sessionFactory.getCurrentSession();
Person personToDelete = getById(id);
session.delete(personToDelete);
}
public void update(Person personToUpdate) {
Session session = sessionFactory.getCurrentSession();
session.update(personToUpdate);
}
}
阅读the documentation了解详情。
答案 1 :(得分:3)
@Transactional
用于该方法。
我们首先在方法级别声明它打开事务,执行操作并关闭事务。
如果操作失败,则会回滚,如果操作成功,则会自动提交
最后约为@Transactional
注释&amp; short。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
">
<!-- Scans the classpath for annotated components that will be auto-registered as Spring beans -->
<context:component-scan base-package="hu.daniel.hari.learn.spring" />
<!-- Activates various annotations to be detected in bean classes e.g: @Autowired -->
<context:annotation-config />
<!-- creating the internal datasource object -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url" value="jdbc:hsqldb:mem://productDb" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:packagesToScan="hu.daniel.hari.learn.spring.orm.model"
p:dataSource-ref="dataSource"
>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="true" />
<property name="showSql" value="true" />
</bean>
</property>
</bean>
<!-- Transactions -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>
package hu.daniel.hari.learn.spring.orm.main;
import hu.daniel.hari.learn.spring.orm.model.Product;
import hu.daniel.hari.learn.spring.orm.service.ProductService;
import java.util.Arrays;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.dao.DataAccessException;
public class SpringOrmMain {
public static void main(String[] args) {
//Create Spring application context
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:/spring.xml");
//Get service from context. (service's dependency (ProductDAO) is autowired in ProductService)
ProductService productService = ctx.getBean(ProductService.class);
//Do some data operation
productService.add(new Product(1, "Bulb"));
productService.add(new Product(2, "Dijone mustard"));
System.out.println("listAll: " + productService.listAll());
//Test transaction rollback (duplicated key)
try {
productService.addAll(Arrays.asList(new Product(3, "Book"), new Product(4, "Soap"), new Product(1, "Computer")));
} catch (DataAccessException dataAccessException) {
}
//Test element list after rollback
System.out.println("listAll: " + productService.listAll());
ctx.close();
}
}