1. 程式人生 > >使用IntelliJ IDEA開發SpringMVC網站(三)資料庫配置

使用IntelliJ IDEA開發SpringMVC網站(三)資料庫配置

六、資料庫配置

      下面,就要通過一個簡單的例子,來介紹SpringMVC如何整合Spring Data JPA(由 Hibernate JPA 提供),來進行強大的資料庫訪問,並通過本章節的講解,更加深刻地認識Controller是如何進行請求處理的,相信看完這一章節,你就可以開始你的開發工作了。

準備工作:

    在src\main\java中新建兩個包:com.gaussic.model、com.gaussic.repository,將在後面用上,如下圖所示:

1、建立Mysql資料庫

      本文的講解使用Mysql資料庫,如果使用其它資料庫的讀者,可以去網上參考其他的配置教程,在此不做太多的敘述。資料庫是一個底層的東西,底層的細節對上層的抽象並沒有太大的影響,因此,只要配置好資料庫,本章的內容仍然是適用於所有資料庫的(貌似如此)。

      假設我們現在要建立一個小小的部落格系統,其資料庫ER圖如下所示(當然這只是一個小小的例子,真實的部落格系統比這要複雜的多):

    新建一個數據庫springdemo,在資料庫中,有兩張表:

    (1)使用者表user:使用者登入資訊,主鍵id設為自增

    (2)博文表blog:儲存使用者發表的博文,主鍵id設為自增,其中有一個外來鍵user_id連結到user表。

    詳細表結構如下圖所示:

使用MySQL Workbench新增外來鍵流程:

注意:在新增外來鍵時,應該根據需求設定,例如右邊紅框中的Foreign Key Options,預設在Delete時是NO ACTION,說明在刪除一個使用者時,如果資料庫中存在該使用者的文章,那麼就無法刪除該使用者,也無法刪除該使用者的所有文章,而如果將該選項改為CASCADE,那麼刪除該使用者,就會同時刪除該使用者所有的文章。通常後者是不太可取的,因為如果發生了刪除使用者的誤操作,很有可能該使用者的內容被連帶刪除,且不可逆,這也是實現真實系統時需要考慮的原因之一。

2、IntelliJ IDEA匯入資料庫

    對於此前所接觸的一些常用的框架中,一張資料表往往對應一個Java Bean。在SpringMVC中,這個Java Bean相當於model。那麼,這個類是否需要自己來寫呢?不需要,利用IntelliJ IDEA可以幫我們自動的生成這些JavaBean。

    首先,右鍵專案,選擇Add Framework Support:

下拉選擇JavaEE Persistence,右邊provider選擇Hibernate:

注:這一部分有一點過時,更新的專案中直接把資料庫的配置放在了mvc-dispatcher-servlet.xml中,但依然要做這一步的操作,為了這一步可以使用Persistence的工具。

關於新的配置,可以翻到部落格底部。

    在這一步結束後,我們可以發現,在resources裡面生成了persistence.xml配置檔案,左邊欄出現了一個Persistence標題(若沒有請點選左下角那個灰框):

    persistemce.xml具體如下:

<?xml version="1.0" encoding="UTF-8"?>
<persistencexmlns="http://java.sun.com/xml/ns/persistence"version="2.0">

    <persistence-unitname="NewPersistenceUnit">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <properties>
            <propertyname="hibernate.connection.url"value=""/>
            <propertyname="hibernate.connection.driver_class"value=""/>
            <propertyname="hibernate.connection.username"value=""/>
            <propertyname="hibernate.connection.password"value=""/>
            <propertyname="hibernate.archive.autodetection"value="class"/>
            <propertyname="hibernate.show_sql"value="true"/>
            <propertyname="hibernate.format_sql"value="true"/>
            <propertyname="hbm2ddl.auto"value="update"/>
        </properties>
    </persistence-unit>
</persistence>

    我們先不著急填寫這個配置檔案。點開左邊欄的Persistence,顯示如下圖所示:

右鍵專案名,選擇Generate Persistence Mapping,再選擇By Database Schema:

出現如下介面,其主要需要配置的地方如下圖紅框所示:

    點選Choose Data Source右邊的三個點選擇資料來源,在彈出的介面左上角選擇“+”,選擇Mysql:

在如下介面填寫主機、埠號、資料庫名、使用者名稱、密碼,如果驅動丟失點選下面的Download可以下載驅動,點選 Test Connection可以測試資料庫是否連線成功:

    在以上介面配置完成後,點OK,第一次使用需要Setup Master Password:

    

    回到如下頁面,package填寫model包(1),勾選Prefer primitive type使用原始資料型別(2),勾選Show default relationships以顯示所有資料庫關係(3),再點選重新整理按鈕(4),將會找到資料庫中的兩個表,勾選兩個資料表(5),再勾選Generate Column Defination以生成每一列的描述資訊(6)。選中blog表然後點選“+”號按鈕,新增外來鍵關係(7)。

    點選OK後,在Database Schema Mapping中可以發現多出了兩個關係,如圖所示:

   再點選OK,稍後,開啟model包,可以看到生成了兩個Java Bean,在SpringMVC中稱為兩個實體,它們對應了資料庫的兩張表:

BlogEntity如下所示(注意把java.sql.Date改為java.util.Date):

package com.gaussic.model;

import javax.persistence.*;
import java.util.Date;

/**
 * Created by dzkan on 2016/3/8.
 */
@Entity
@Table(name = "blog", schema = "springdemo", catalog = "")
public classBlogEntity{
    private int id;
    private String title;
    private String content;
    private Date pubDate;
    private UserEntity userByUserId;

    @Id
    @Column(name = "id", nullable = false)
    publicintgetId(){
        return id;
    }

    publicvoidsetId(int id){
        this.id = id;
    }

    @Basic
    @Column(name = "title", nullable = false, length = 100)
    public String getTitle(){
        return title;
    }

    publicvoidsetTitle(String title){
        this.title = title;
    }

    @Basic
    @Column(name = "content", nullable = true, length = 255)
    public String getContent(){
        return content;
    }

    publicvoidsetContent(String content){
        this.content = content;
    }

    @Basic
    @Column(name = "pub_date", nullable = false)
    public Date getPubDate(){
        return pubDate;
    }

    publicvoidsetPubDate(Date pubDate){
        this.pubDate = pubDate;
    }

    @Override
    publicbooleanequals(Object o){
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        BlogEntity that = (BlogEntity) o;

        if (id != that.id) return false;
        if (title != null ? !title.equals(that.title) : that.title != nullreturn false;
        if (content != null ? !content.equals(that.content) : that.content != nullreturn false;
        if (pubDate != null ? !pubDate.equals(that.pubDate) : that.pubDate != nullreturn false;

        return true;
    }

    @Override
    publicinthashCode(){
        int result = id;
        result = 31 * result + (title != null ? title.hashCode() : 0);
        result = 31 * result + (content != null ? content.hashCode() : 0);
        result = 31 * result + (pubDate != null ? pubDate.hashCode() : 0);
        return result;
    }

    @ManyToOne
    @JoinColumn(name = "user_id", referencedColumnName = "id", nullable = false)
    public UserEntity getUserByUserId(){
        return userByUserId;
    }

    publicvoidsetUserByUserId(UserEntity userByUserId){
        this.userByUserId = userByUserId;
    }
}

    再看UserEntity:

package com.gaussic.model;

import javax.persistence.*;
import java.util.Collection;

/**
 * Created by dzkan on 2016/3/8.
 */
@Entity
@Table(name = "user", schema = "springdemo", catalog = "")
public classUserEntity{
    private int id;
    private String nickname;
    private String password;
    private String firstName;
    private String lastName;
    private Collection<BlogEntity> blogsById;

    @Id
    @Column(name = "id", nullable = false)
    publicintgetId(){
        return id;
    }

    publicvoidsetId(int id){
        this.id = id;
    }

    @Basic
    @Column(name = "nickname", nullable = false, length = 45)
    public String getNickname(){
        return nickname;
    }

    publicvoidsetNickname(String nickname){
        this.nickname = nickname;
    }

    @Basic
    @Column(name = "password", nullable = false, length = 45)
    public String getPassword(){
        return password;
    }

    publicvoidsetPassword(String password){
        this.password = password;
    }

    @Basic
    @Column(name = "first_name", nullable = true, length = 45)
    public String getFirstName(){
        return firstName;
    }

    publicvoidsetFirstName(String firstName){
        this.firstName = firstName;
    }

    @Basic
    @Column(name = "last_name", nullable = true, length = 45)
    public String getLastName(){
        return lastName;
    }

    publicvoidsetLastName(String lastName){
        this.lastName = lastName;
    }

    @Override
    publicbooleanequals(Object o){
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        UserEntity that = (UserEntity) o;

        if (id != that.id) return false;
        if (nickname != null ? !nickname.equals(that.nickname) : that.nickname != nullreturn false;
        if (password != null ? !password.equals(that.password) : that.password != nullreturn false;
        if (firstName != null ? !firstName.equals(that.firstName) : that.firstName != nullreturn false;
        if (lastName != null ? !lastName.equals(that.lastName) : that.lastName != nullreturn false;

        return true;
    }

    @Override
    publicinthashCode(){
        int result = id;
        result = 31 * result + (nickname != null ? nickname.hashCode() : 0);
        result = 31 * result + (password != null ? password.hashCode() : 0);
        result = 31 * result + (firstName != null ? firstName.hashCode() : 0);
        result = 31 * result + (lastName != null ? lastName.hashCode() : 0);
        return result;
    }

    @OneToMany(mappedBy = "userByUserId")
    public Collection<BlogEntity> getBlogsById(){
        return blogsById;
    }

    publicvoidsetBlogsById(Collection<BlogEntity> blogsById){
        this.blogsById = blogsById;
    }
}

3、配置資料庫

    既然資料庫已經匯入了,那麼前期準備工作基本完成,還需要進行最終的配置。

    首先,開啟mvc-dispatcher-servlet.xml,新增下列配置(如果某些地方報錯,請選中並按Alt + Insert補全配置):

<!-- 表示JPA Repository所在的包 -->
<jpa:repositoriesbase-package="com.gaussic.repository"/>

<!-- 連結到persistence.xml -->
<beanid="entityManagerFactory"class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
    <propertyname="persistenceUnitName"value="defaultPersistenceUnit"/>
</bean>

<!-- 事務管理 -->
<beanid="transactionManager"class="org.springframework.orm.jpa.JpaTransactionManager">
    <propertyname="entityManagerFactory"ref="entityManagerFactory"/>
</bean>

<!-- 開啟事務管理註解 -->
<tx:annotation-driventransaction-manager="transactionManager"/>

    講解:

    (1) jpa:repositories:這一部分涉及到資料庫的介面,將在後面詳解;

    (2)entityManagerFactory:實體管理器工廠,讀取persistence.xml配置;

    (3)transactionManager:事務管理器,利用entityManager進行事務管理;

    (4)tx:annotation-driven:開啟事務管理器的註解驅動,可以使用註解的方法操縱資料庫。

整體如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:jpa="http://www.springframework.org/schema/data/jpa"xmlns:tx="http://www.springframework.org/schema/tx"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/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
       http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd 
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!--指明 controller 所在包,並掃描其中的註解-->
    <context:component-scanbase-package="com.gaussic.controller"/>

    <!-- 靜態資源(js、image等)的訪問 -->
    <mvc:default-servlet-handler/>

    <!-- 開啟註解 -->
    <mvc:annotation-driven/>

    <!--ViewResolver 檢視解析器-->
    <!--用於支援Servlet、JSP檢視解析-->
    <beanid="jspViewResolver"class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <propertyname="viewClass"value="org.springframework.web.servlet.view.JstlView"/>
        <propertyname="prefix"value="/WEB-INF/pages/"/>
        <propertyname="suffix"value=".jsp"/>
    </bean>

    <!-- 表示JPA Repository所在的包 -->
    <jpa:repositoriesbase-package="com.gaussic.repository"/>

    <!-- 連結到persistence.xml -->
    <beanid="entityManagerFactory"class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
        <propertyname="persistenceUnitName"value="defaultPersistenceUnit"/>
    </bean>

    <!-- 事務管理 -->
    <beanid="transactionManager"class="org.springframework.orm.jpa.JpaTransactionManager">
        <propertyname="entityManagerFactory"ref="entityManagerFactory"/>
    </bean>

    <!-- 開啟事務管理註解 -->
    <tx:annotation-driventransaction-manager="transactionManager"/>
</beans>

    下面,填充persistence.xml,將persistence-unit的name改為 defaultPersistenceUnit。在下面的檔案中,我添加了一些更為詳細的配置:

<?xml version="1.0" encoding="UTF-8"?>
<persistencexmlns="http://java.sun.com/xml/ns/persistence"version="2.0">

    <persistence-unitname="defaultPersistenceUnit"transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <properties>
            <!-- 使用MySQL方言 -->
            <propertyname="hibernate.dialect"value="org.hibernate.dialect.MySQL5Dialect"/>
            <!-- 資料庫連線的URL地址 -->
            <propertyname="hibernate.connection.url"value="jdbc:mysql://localhost:3306/springdemo"/>
            <!-- 資料庫連線的驅動 -->
            <propertyname="hibernate.connection.driver_class"value="com.mysql.jdbc.Driver"/>
            <!-- 資料庫連線的使用者名稱 -->
            <propertyname="hibernate.connection.username"value="root"/>
            <!-- 資料庫連線的密碼 -->
            <propertyname="hibernate.connection.password"value="111111"