11 months ago

這幾個月工作實在太繁忙,沒有太多時間考慮Blog的更新,由於長期加班也在想,這麼努力工作,得到的回報是不是很值得呢?畢竟一直做重複性的工作,量多但是並沒有多大挑戰性,研究技術的時間整整被壓縮,這樣下去競爭力變差也不是公司的損失,是個人的損失吧?好了,今天就不多說了,要來介紹一下Spring中是如何使用Hibernate、JPA的。

然後我再多說題外話一下,有大大於FB敲我,這邊抱歉沒有回應,這幾個月有點忙,SORRY!!

蝦咪系 Hierbernate

Hibernate ORM是於JAVA上使用的一種ORM(Object Relational Mapping)工具,我覺得中文聽起來很憋扭啊!!物件對應關係、物件映射關係,隨便啦!!大家可以明白,這種工具就是將物件與物件的關係對應到資料表與資料表之間的關係,我們可以利用一些設定將這些物件關係設定好後,即可達到一些物件關聯的效果,這樣做我們也不需要去做這些SQL語法上的撰寫,也不需要去管理Connection,可以減少程式碼。

蝦咪系 JPA

JPA全名為Java Persistence API,他提供一個永續儲存的標準、規範,也就是這些ORM接口,Hibernate則為接口的實現,當然JPA跟Hibernate可能很像,因為JPA*致敬*了Hibernate才產生出來的嘛!!

開戰啦!!

Dependencies

//Spring

def springVersion = '5.0.1.RELEASE'
compile group: 'org.springframework', name: 'spring-context', version: "${springVersion}"
compile group: 'org.springframework', name: 'spring-orm', version: "${springVersion}"
compile group: 'org.springframework', name: 'spring-test', version: "${springVersion}"

//DBCP (Connection Pool)

compile group: 'org.apache.commons', name: 'commons-dbcp2', version: "2.0"

//Hibernate

def hibernateVersion = '5.2.10.Final'
compile group: 'org.hibernate', name: 'hibernate-core', version: "${hibernateVersion}"

//SQL Server

def sqlVersion = '6.1.0.jre8'
compile group: 'com.microsoft.sqlserver', name: 'mssql-jdbc', version: "${sqlVersion}"

//Log4j 2

def log4jVersion = '2.8.2'
compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: "${log4jVersion}"
compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: "${log4jVersion}"
compile group: 'org.apache.logging.log4j', name: 'log4j-jcl', version: "${log4jVersion}"

//common

compile group: 'commons-collections', name: 'commons-collections', version: '3.2'

//test

testCompile group: 'junit', name: 'junit', version: '4.+'

Configuration

以下將會介紹兩種設定方式,那麼基本上是一樣的,但目前個人偏好JavaConfig方式進行,好處在於找問題時連Spring Boot的文章也可以稍微看看,畢竟Spring Boot是沒有XML設置的。

Java Config Spring Configuration

@Configuration
@EnableTransactionManagement
public class PersistenceJpaConfig {

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
        entityManagerFactory.setDataSource(dataSource());
        entityManagerFactory.setPackagesToScan("com.spring.example");
        
        JpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
        entityManagerFactory.setJpaVendorAdapter(jpaVendorAdapter);
        
        Properties properties = new Properties();
        properties.setProperty("hibernate.dialect", "org.hibernate.dialect.SQLServer2012Dialect");
        properties.setProperty("hibernate.show_sql", "true");
        entityManagerFactory.setJpaProperties(properties);
        
        return entityManagerFactory;
    }
    
    @Bean
    public BasicDataSource dataSource() {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
        dataSource.setUrl("jdbc:sqlserver://localhost;databaseName=andy");
        dataSource.setUsername( "admin" );
        dataSource.setPassword( "admin" );
          
        return dataSource;
    }
    
    @Bean
    public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactory);
        return transactionManager;
    }
    
    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
        return new PersistenceExceptionTranslationPostProcessor();
    }
    
    @Bean
    public FruitDao fruitDao() {
        FruitDao fruitDao = new FruitDaoImpl();
        return fruitDao;
    }
    
    @Bean
    public FruitBo fruitBo() {
        FruitBoImpl fruitBo = new FruitBoImpl();
        fruitBo.setFruitDao(fruitDao());
        return fruitBo;
    }
    
}

XML Spring Configuration

<?xml version="1.0" encoding="UTF-8"?>
<beans 
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-4.1.xsd">  

    <context:component-scan base-package="com.spring.example.*" />
        
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
      <property name="dataSource" ref="dataSource" />
      <property name="packagesToScan" value="com.spring.example" />
      <property name="jpaVendorAdapter">
         <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
      </property>
      <property name="jpaProperties">
         <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.SQLServer2012Dialect</prop>
         </props>
      </property>
   </bean>

    <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
        <property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
        <property name="url" value="jdbc:sqlserver://localhost;databaseName=andy" />
        <property name="username" value="admin" />
        <property name="password" value="admin" />
    </bean>
    
    <tx:annotation-driven transaction-manager="transactionManager" />
    
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" /> 
    </bean>

    <bean id="persistenceExceptionTranslationPostProcessor" class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
 
   <bean id="fruitBo" class="com.spring.example.FruitBoImpl" >
        <property name="fruitDao" ref="fruitDao" />
   </bean>

   <bean id="fruitDao" class="com.spring.example.FruitDaoImpl" />

</beans>

Entity

方才說過ORM就是將物件與物件的關係對上資料庫,因此我們這邊設定方法就是一個Object對上一張Table。

Fruit

水果Der物件對上Table名稱為FRUIT的資料表,在Hibernate底下是一定要有PK的,然而資料庫本身確實就該有PK或者多欄位組成的PK,這邊PK很簡單的就設定為流水號,剩餘的就是哪個欄位對上哪個參數。

@Entity
@Table(name = "FRUIT")
public class Fruit {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    
    @Column(name = "NAME")
    private String name;
    
    @Column(name = "PRICE")
    private int price;

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Fruit [id=" + id + ", name=" + name + ", price=" + price + "]";
    }
    
}

Data Access Object

FruitDao

public interface FruitDao {

    public void save(Fruit fruit);
    
    public void update(Fruit fruit);
    
    public void delete(Fruit fruit);
    
    public List<Fruit> getFruits();
    
}

FruitDaoImpl

這邊我稍微講一下,如果會使用到新增、刪除、修改之餘,就要加上Transactional Annotation告訴JPA我們的動作。

@Repository
public class FruitDaoImpl implements FruitDao {

    @PersistenceContext
    private EntityManager entityManager;
    
    @Transactional
    public void save(Fruit fruit) {
        entityManager.persist(fruit);
    }

    @Transactional
    public void update(Fruit fruit) {
        entityManager.merge(fruit);
    }

    @Transactional
    public void delete(Fruit fruit) {
        entityManager.remove(fruit);
    }

    @SuppressWarnings("unchecked")
    public List<Fruit> getFruits() {
        return entityManager.createQuery("Select f from Fruit f").getResultList();
    }

}

Business Object

FruitBo

public interface FruitBo {
    
    public void save(Fruit fruit);
    
    public void update(Fruit fruit);
    
    public void delete(Fruit fruit);
    
    public List<Fruit> getFruits();
    
}

FruitBoImpl

public class FruitBoImpl implements FruitBo {

    private FruitDao fruitDao;
    
    public void setFruitDao(FruitDao fruitDao) {
        this.fruitDao = fruitDao;
    }
    
    public void save(Fruit fruit) {
        fruitDao.save(fruit);
    }

    public void update(Fruit fruit) {
        fruitDao.update(fruit);
    }

    public void delete(Fruit fruit) {
        fruitDao.delete(fruit);
    }

    public List<Fruit> getFruits() {
        return fruitDao.getFruits();
    }

}

Test

@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration(locations = "classpath:hibernate.cfg.xml")

@ContextConfiguration(classes = PersistenceJpaConfig.class)
public class HibernateTest extends AbstractJUnit4SpringContextTests {
    
    @Autowired
    private FruitBo fruitBo; 
    
    @Test
    public void hibernateTest() {
        
        Fruit fruit = new Fruit();
        fruit.setName("Strawberry");
        fruit.setPrice(300);
        
        fruitBo.save(fruit);
        
        if(fruitBo.getFruits().size() > 0) {
            assertTrue(true);
        } else {
            assertTrue(false);
        }
        
    }
    
}

Reference

Hibernate (framework)
淺談【物件關係對映(Object Relational Mapping ORM)】
A Guide to Hibernate with Spring 4

← [Web Security] What is Token ? [Java] SQL Exception Handle →
 
comments powered by Disqus