《Spring實戰(zhàn)》-第十一章:利用對象-關(guān)系映射持久化數(shù)據(jù)(Spring整合Hibernate)

慢來比較快,虛心學(xué)技術(shù)

Ⅰ、Hibernate架構(gòu)體系分析

先來了解一下Hibernate的框架體系,下圖為官方Hibernate簡要體系結(jié)構(gòu):

Hibernate通過持久化對象Persistent Objects(PO)對數(shù)據(jù)庫進行操作,底層數(shù)據(jù)庫操作 對于應(yīng)用程序來說是透明的,應(yīng)用程序無需關(guān)心JDBC操作,底層數(shù)據(jù)庫連接、數(shù)據(jù)庫訪問實現(xiàn)、事務(wù)控制,而是直接以面向?qū)ο蠓绞竭M行持久層的操作。

Hibernate詳細的框架體系如下:

  1. SessionFactory:****是依賴于ConnectionProvider的會話和客戶端工廠。 它擁有數(shù)據(jù)的二級緩存(可選)。 org.hibernate.SessionFactory接口提供了工廠方法來獲取Session的對象。(實現(xiàn)了****EntityManagerFactory****接口)
  2. Session:****應(yīng)用程序與持久層之間交互操作的一個單線程對象。所有的持久化對象必須在Session管理下才能進行持久化操作。它底層封裝了JDBC連接,是Transaction工廠。(實現(xiàn)了****EntityManager****接口)
  3. 持久化對象(PO):系統(tǒng)創(chuàng)建的POJO實例,一旦與特定的Session關(guān)聯(lián),并對應(yīng)數(shù)據(jù)表的指定記錄,該對象就處于持久化狀態(tài)。
  4. 事務(wù)(Transaction):代表一次原子操作,Hibernate事務(wù)是對底層具體的JDBC,JTA以及CORBA事務(wù)的抽象。
  5. 連接提供者(ConnectionProvider):生成JDBC連接的工廠,通過抽象將應(yīng)用程序與底層的DataSource或DriverManager隔離開。
  6. 事務(wù)工廠(TransactionFactory):它是一個事務(wù)工廠,是一個可選項。

如下是一次數(shù)據(jù)庫請求操作的執(zhí)行過程:

①應(yīng)用程序調(diào)用Configuration讀取配置文件(映射文件和hibernate.propertise),并據(jù)此生成SessionFactory工廠對象。

SessionFactory生產(chǎn)Session操作對象,通過Session對象對數(shù)據(jù)庫執(zhí)行CRUD操作,同時生成Transaction對象

③如果Session執(zhí)行操作正常,Transaction提交事務(wù)將結(jié)果真正生成至數(shù)據(jù)庫,如果操作異常,則執(zhí)行事務(wù)回滾

Ⅱ、Spring整合使用Hibernate

①引入依賴:

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>

    <!--logback日志實現(xiàn)引入-->
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-core</artifactId>
        <version>1.1.7</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-access</artifactId>
        <version>1.1.7</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.1.7</version>
    </dependency>

    <!--slf4j日志門面引入-->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.7</version>
    </dependency>

    <!--引入alibaba的數(shù)據(jù)庫連接池-->
    <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.10</version>
    </dependency>

    <!--引入Spring支持-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>${org.springframework.version}</version>
    </dependency>

    <!--引入Spring事務(wù)-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>${org.springframework.version}</version>
    </dependency>

    <!--引入Spring對ORM框架的支持依賴-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-orm</artifactId>
        <version>${org.springframework.version}</version>
    </dependency>

    <!--引入Hibernate支持-->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>${hibernate.version}</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>${hibernate.version}</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-ehcache</artifactId>
        <version>${hibernate.version}</version>
    </dependency>

    <dependency>
        <groupId>net.sf.ehcache</groupId>
        <artifactId>ehcache</artifactId>
        <version>2.9.0</version>
    </dependency>

    <!--引入數(shù)據(jù)庫驅(qū)動-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
</dependencies>

②編寫實體類:BaseBean

@Data//lombok注解,默認添加setter,getter方法
@ToString//lombok注解,默認改寫toString()方法
public class BaseBean {

    private Integer id;

    private String name;

    private Integer age;
}

③編寫實體類映射文件:BaseBean.hbm.xml,將BaseBean實體類與數(shù)據(jù)庫表basebean關(guān)聯(lián)映射

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">-->

        <!-- Generated 2016-3-15 16:30:05 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
    <class name="com.my.spring.bean.BaseBean" table="basebean">
        <id name="id" type="java.lang.Integer" column="id">
            <generator class="native" />
        </id>
        <property name="name" type="java.lang.String" column="name"/>
        <property name="age" type="java.lang.Integer" column="age"/>
    </class>
</hibernate-mapping>

映射文件和實體類位置如下:

④編寫數(shù)據(jù)庫資源文件:dataSource.properties

#指定數(shù)據(jù)庫驅(qū)動
jdbc.driver = com.mysql.jdbc.Driver

#指定數(shù)據(jù)庫url
jdbc.url = jdbc:mysql://localhost:3306/spring

#指定數(shù)據(jù)庫用戶
jdbc.username = spring

#指定數(shù)據(jù)庫用戶密碼
jdbc.password = spring

#指定使用的數(shù)據(jù)庫連接池
druid.dataSource=com.alibaba.druid.pool.DruidDataSource

#指定最大活躍連接數(shù)
druid.maxActive=10

#指定等待連接超時時間,單位毫秒
druid.maxWait=10000

#指定間隔掃描連接時間,檢測需要關(guān)閉的空閑連接,單位是毫秒
druid.timeBetweenEvictionRunsMillis=60000

⑤編寫Spring配置文件:application.xml

<?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"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--開啟 spring注解掃描-->
    <context:annotation-config/>
     <!--配置組件掃描范圍-->
    <context:component-scan base-package="com.my.spring"></context:component-scan>

    <!-- 導(dǎo)入資源文件 -->
    <context:property-placeholder location="classpath:datasource.properties"/>

    <!--配置數(shù)據(jù)庫連接池-->
    <bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
        <property name="driverClassName" value="${jdbc.driver}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
        <property name="maxActive" value="${druid.maxActive}"></property>
        <property name="maxWait" value="${druid.maxWait}"></property>
        <property name="timeBetweenEvictionRunsMillis" value="${druid.timeBetweenEvictionRunsMillis}"></property>
    </bean>

    <!--配置Hibernate下的SessionFactory-->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean" lazy-init="false">
        <!--注入數(shù)據(jù)庫-->
        <property name="dataSource" ref="dataSource" />
        <!-- //加載實體類的映射文件位置及名稱 -->
        <property name="mappingLocations" value="classpath*:/com/my/spring/bean/*.hbm.xml"></property>

        <!--配置hibernate的主配置屬性-->
        <property name="hibernateProperties">
            <props>
                 <!--是否顯示執(zhí)行sql-->
                <prop key="hibernate.show_sql">true</prop>
                 <!--數(shù)據(jù)庫表策略-->
                <prop key="hibernate.hbm2ddl.auto">update</prop>
                 <!--數(shù)據(jù)庫方言-->
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
            </props>
        </property>
    </bean>

    <!-- 配置Spring聲明式事務(wù) -->
    <bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
        <property name="sessionFactory" ref="sessionFactory"></property>
    </bean>

    <!--開啟注解事務(wù)-->
    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

⑥編寫數(shù)據(jù)庫操作接口和實現(xiàn)類:BaseBeanRepository.java&BaseBeanRepositoryImpl.java

public interface BaseRepository {

    /**
     *  保存記錄
     * @param baseBean
     * @return
     */
    void save(BaseBean baseBean);

    /**
     * 獲取所有記錄
     * @return
     */
    List<BaseBean> findAll();

    /**
     * 獲取指定id記錄
     * @param id
     * @return
     */
    BaseBean findOne(Integer id);
}

@Repository
public class BaseRepositoryImpl implements BaseRepository {

    //注入sessionFactory,用于獲取session
    @Autowired
    private SessionFactory sessionFactory;

    //獲取session
    public Session getSession(){
        return sessionFactory.getCurrentSession();
    }

    @Override
    public void save(BaseBean baseBean) {
        this.getSession().saveOrUpdate(baseBean);
    }

    @Override
    public List<BaseBean> findAll() {
        String hql = "FROM BaseBean";
        Query query = this.getSession().createQuery(hql);
        return query.list();
    }

    @Override
    public BaseBean findOne(Integer id) {
        String hql = "FROM BaseBean Where id=?";
        Query query = this.getSession().createQuery(hql).setParameter(0,id);
        return (BaseBean) query.uniqueResult();
    }
}

⑦編寫邏輯處理接口和實現(xiàn)類:BaseService.java&BaseServiceImpl.java

public interface BaseService {
    /**
     *  保存記錄
     * @param baseBean
     * @return
     */
    void save(BaseBean baseBean);

    /**
     * 獲取所有記錄
     * @return
     */
    List<BaseBean> findAll();

    /**
     * 獲取指定id記錄
     * @param id
     * @return
     */
    BaseBean findOne(Integer id);
}

@Component
@Transactional(rollbackFor = {RuntimeException.class})
public class BaseServiceImpl implements BaseService {

    //注入baseRepository操作類
    @Autowired
    private BaseRepository baseRepository;

    @Override
    public void save(BaseBean baseBean) {
        this.baseRepository.save(baseBean);
    }

    @Override
    public List<BaseBean> findAll() {
        return this.baseRepository.findAll();
    }

    @Override
    public BaseBean findOne(Integer id) {
        return this.baseRepository.findOne(id);
    }
}

⑧編寫測試類

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:application.xml"})
public class AppTest 
{
    @Autowired
    private BaseService baseService;

    @Autowired
    private ApplicationContext applicationContext;

    @Test
    public void testHibernate() throws SQLException {
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames){
            System.out.println(beanDefinitionName);
        }
    }

    @Test
    public void testSave(){
        BaseBean baseBean = new BaseBean();
        baseBean.setName("hibernate bean");
        baseBean.setAge(50);
        this.baseService.save(baseBean);
    }

    @Test
    public void testFindAll(){
        List<BaseBean> list = this.baseService.findAll();
        if(null==list||list.isEmpty()){
            System.out.println("空表");
        }else{
            for (BaseBean baseBean : list){
                System.out.println(baseBean.toString());
            }
        }
    }
}

⑨測試結(jié)果:

執(zhí)行testHibernate()

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.annotation.internalPersistenceAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
baseRepositoryImpl
baseServiceImpl
org.springframework.context.support.PropertySourcesPlaceholderConfigurer#0
dataSource
sessionFactory
transactionManager
org.springframework.transaction.config.internalTransactionalEventListenerFactory
org.springframework.aop.config.internalAutoProxyCreator
org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0
org.springframework.transaction.interceptor.TransactionInterceptor#0
org.springframework.transaction.config.internalTransactionAdvisor

執(zhí)行 testSave()

2019-03-18 11:34:31.537 DEBUG org.hibernate.SQL - insert into basebean (name, age) values (?, ?)
Hibernate: insert into basebean (name, age) values (?, ?)
2019-03-18 11:34:31.556 DEBUG org.hibernate.id.IdentifierGeneratorHelper - Natively generated identity: 2

執(zhí)行testFindAll()

2019-03-18 11:37:22.901 DEBUG org.hibernate.SQL - select basebean0_.id as id1_0_, basebean0_.name as name2_0_, basebean0_.age as age3_0_ from basebean basebean0_
Hibernate: select basebean0_.id as id1_0_, basebean0_.name as name2_0_, basebean0_.age as age3_0_ from basebean basebean0_

BaseBean(id=1, name=hibernate bean, age=50)
BaseBean(id=2, name=hibernate bean, age=50)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容