Beginning Spring学习笔记——第5章(二)Spring的JPA支持

Spring的JPA支持的好处


  • 更容易且更强大的持久化单元配置,不必使用META-INF/persistence.xml
  • 更容易测试
  • 自动EntityManager管理,且可注入DAO Bean中
  • 常见的数据访问异常,异常层次结构变为Spring的
  • 集成事务管理

在Spring容器中配置JPA


Spring在同一个项目中提供三种不同方法配置EntityManagerFactory。

  • LocalEntityManagerFactoryBean
    最基础且功能最有限的方法,从META-INF/persistence.xml中读取JPA配置,不允许使用Spring管理的DataSource实例且不支持分布式事务管理
  • 通过JNDI进行EntityManagerFactory查找
    此时的Spring EntityManagerFactory Bean只不过是一个从JNDI获取的持久化单元委托
  • LocalContainerEntityFactoryBean,最强大和灵活的JPA配置方法,对EntityManagerFactory完全控制
使用LocalContainerEntityManagerFactoryBean配置和使用JPA

接上一节的Book和Student类创建配置类

@Configuration
public class Ch5Configuration {

    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("org.h2.Driver");
        dataSource.setUrl("jdbc:h2:tcp://localhost/~/test");
        dataSource.setUsername("sa");
        dataSource.setPassword("");
        return dataSource;
    }
    private Map<String,?> jpaProperties() {
        Map<String,String> jpaPropertiesMap = new HashMap<String,String>();
        jpaPropertiesMap.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
        jpaPropertiesMap.put("hibernate.hbm2ddl.auto", "update");
        return jpaPropertiesMap;
    }
    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean factoryBean = 
            new LocalContainerEntityManagerFactoryBean();
        factoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
        factoryBean.setDataSource(dataSource());
        factoryBean.setPackagesToScan("com.wiley.beginningspring.ch5");
        factoryBean.setJpaPropertyMap(jpaProperties());
        return factoryBean;
    }


}

为使用Spring管理的DataSource和EntityManagerFactory,主函数中也要创建Spring容器

public class Main {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(
                Ch5Configuration.class);
        EntityManagerFactory entityManagerFactory = applicationContext
                .getBean(EntityManagerFactory.class);
        EntityManager entityManager = entityManagerFactory
                .createEntityManager();
        EntityTransaction transaction = entityManager.getTransaction();
        transaction.begin();

        Student student = new Student();
        student.setFirstName("Madoka");
        student.setLastName("Kaname");

        entityManager.persist(student);

        transaction.commit();
        entityManager.close();

    }

}

完成插入操作后查看数据库:
STUDENT
学生成功被插入。

基于纯JPA实现DAO


可以在字段或方法级别使用@PersistenceContext和@PersistenceUnit注解,前者表示对EntityManagerFactory的依赖,后者表示对EntityManager的依赖

使用@PersistenceUnit获取EntityManagerFactory

此时需要在Dao实现类中加入EntityManagerFactory字段并在其上放置@PersistenceUnit注解将entityManagerFactory注入到DAO类中。

public class StudentDaoJpaImpl {

    @PersistenceUnit
    private EntityManagerFactory entityManagerFactory;

    public void save(Student student) {
        EntityManager entityManager = entityManagerFactory
                .createEntityManager();
        EntityTransaction transaction = entityManager.getTransaction();
        transaction.begin();
        entityManager.persist(student);
        transaction.commit();
        entityManager.close();
    }
}

此时还要在配置文件中加入DAO类的Bean:

    @Bean
    public StudentDaoJpaImpl studentDao() {
        StudentDaoJpaImpl dao = new StudentDaoJpaImpl();
        return dao;
    }

然后在主函数里用该DAO类插入一个Student实例:

public class Main {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(
                Ch5Configuration.class);

        StudentDaoJpaImpl dao = applicationContext.getBean(StudentDaoJpaImpl.class);

        Student student = new Student();
        student.setFirstName("Sayaka");
        student.setLastName("Miki");

        dao.save(student);
    }
}

运行程序发现插入成功
插入成功

使用@PersistenceContext获取EntityManager

此时要用@EnableTransactionManagement注解标识配置类启用Spring容器管理事务,新配置类为:

@Configuration
@EnableTransactionManagement
public class Ch5Configuration {

    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("org.h2.Driver");
        dataSource.setUrl("jdbc:h2:tcp://localhost/~/test");
        dataSource.setUsername("sa");
        dataSource.setPassword("");
        return dataSource;
    }
    private Map<String,?> jpaProperties() {
        Map<String,String> jpaPropertiesMap = new HashMap<String,String>();
        jpaPropertiesMap.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
        jpaPropertiesMap.put("hibernate.hbm2ddl.auto", "update");
        return jpaPropertiesMap;
    }
    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean factoryBean = 
            new LocalContainerEntityManagerFactoryBean();
        factoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
        factoryBean.setDataSource(dataSource());
        factoryBean.setPackagesToScan("com.wiley.beginningspring.ch5");
        factoryBean.setJpaPropertyMap(jpaProperties());
        return factoryBean;
    }

    @Bean
    public StudentDaoJpaImpl studentDao() {
        StudentDaoJpaImpl dao = new StudentDaoJpaImpl();
        return dao;
    }

    @Bean
    @Autowired
    public PlatformTransactionManager transactionManager(
        EntityManagerFactory entityManagerFactory) {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactory);
        return transactionManager;
    }

    @Bean
    public BookDao bookDao() {
        BookDaoJpaImpl bean = new BookDaoJpaImpl();
        return bean;
    }

    @Bean
    public BookService bookService() {
        BookServiceImpl bean = new BookServiceImpl();
        bean.setBookDao(bookDao());
        return bean;
    }

}

然后创建BookDao接口和它的实现类进行持久化操作。由于@PersistenceContext注解是与EntityManager绑定,因此被注入的是EntityManager实例。

public interface BookDao {
    public void save(Book book);
}

public class BookDaoJpaImpl implements BookDao {
    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public void save(Book book) {
        entityManager.persist(book);
    }
}

再创建服务层的BookService接口和其实现类处理事务管理。

public interface BookService {
    public void save(Book book);
}

@Transactional
public class BookServiceImpl implements BookService {
    private BookDao bookDao;

    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }

    @Override
    public void save(Book book) {
        bookDao.save(book);
    }

}

以上二者的Bean都已经定义在了新配置文件中完成了向服务层注入dao层。
最后在主函数中执行对bookService的Bean查找,对新的Book实体进行持久化操作。

public class Main {
    public static void main(String[] args) {
        ApplicationContext applicationContext = 
            new AnnotationConfigApplicationContext(Ch5Configuration.class);

        BookService bookService = applicationContext.getBean(BookService.class);

        Book book = new Book();
        book.setName("The Order of Things");
        bookService.save(book);
    }
}

运行得到结果,成功插入书籍
运行结果

处理和转换异常


只需要用@Repository注解标注DAO实现类,

@Repository
public class BookDaoJpaImpl implements BookDao {
    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public void save(Book book) {
        entityManager.persist(book);
    }
}

然后在配置类中加入PersistenceExceptionTranslationPostProcessor的Bean,

    @Bean
    public static PersistenceExceptionTranslationPostProcessor 
        persistenceExceptionTranslationPostProcessor() {
        PersistenceExceptionTranslationPostProcessor bean = 
        new PersistenceExceptionTranslationPostProcessor();
        return bean;
    }

就可以在服务层通过一个try-catch语句捕捉转化为DataAccessException的异常了。

    @Override
    public void save(Book book) {
        try{
            //Perform some business logic here
            bookDao.save(book);
        } catch (DataAccessException ex) {
            //handle the data access exception without depending on particular data access technology used beneath
    }

在Spring环境中进一步配置JPA

JpaDialect

通过该接口可以配置如下高级功能:

  • 应用特定事务语义,比如自定义隔离级别或者事务超时
  • 获取事务性JDBC连接,以便向基于JDBC的DAO公开
  • 将PersistenceExcept转换到Spring DataAccessException的高级功能

默认实现为不提供任何上述功能的DefaultJpaDialect,使用上述功能需要指定特定方言类,比如HibernateJpaDialect。

JpaVendorAdapter

用于激活与供应商有关的高级功能,例如可以将LocalContainerEntityManagerFactoryBean中一下代码注释掉集中配置和管理:

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean factoryBean = 
            new LocalContainerEntityManagerFactoryBean();
        factoryBean.setDataSource(dataSource());
        //factoryBean.setJpaPropertyMap(jpaProperties());
        //factoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
        //factoryBean.setJpaDialect(new HibernateJpaDialect());

        factoryBean.setJpaVendorAdapter(jpaVendorAdapter());
        return factoryBean;
    }


    @Bean
    public JpaVendorAdapter jpaVendorAdapter() {
        HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
        jpaVendorAdapter.setGenerateDdl(true);
        jpaVendorAdapter.setDatabase(Database.H2);
        return jpaVendorAdapter;
    }
JPA加载时编制

在配置类上添加@EnableLoadTimeWeaving启用加载时编织

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值