轉載請註明出處:Gaussic。java
注:在閱讀本文前,請先閱讀:mysql
使用IntelliJ IDEA開發SpringMVC網站(一)開發環境git
使用IntelliJ IDEA開發SpringMVC網站(二)框架配置github
訪問GitHub下載最新源碼:https://github.com/gaussic/SpringMVCDemoweb
下面,就要經過一個簡單的例子,來介紹SpringMVC如何集成Spring Data JPA(由 Hibernate JPA 提供),來進行強大的數據庫訪問,並經過本章節的講解,更加深入地認識Controller是如何進行請求處理的,相信看完這一章節,你就能夠開始你的開發工做了。spring
準備工做:sql
在src\main\java中新建兩個包:com.gaussic.model、com.gaussic.repository,將在後面用上,以下圖所示:數據庫
本文的講解使用Mysql數據庫,若是使用其它數據庫的讀者,能夠去網上參考其餘的配置教程,在此不作太多的敘述。數據庫是一個底層的東西,底層的細節對上層的抽象並無太大的影響,所以,只要配置好數據庫,本章的內容仍然是適用於全部數據庫的(貌似如此)。spring-mvc
假設咱們如今要創建一個小小的博客系統,其數據庫ER圖以下所示(固然這只是一個小小的例子,真實的博客系統比這要複雜的多):tomcat
新建一個數據庫springdemo,在數據庫中,有兩張表:
(1)用戶表user:用戶登陸信息,主鍵id設爲自增;
(2)博文表blog:儲存用戶發表的博文,主鍵id設爲自增,其中有一個外鍵user_id連接到user表。
詳細表結構以下圖所示:
使用MySQL Workbench添加外鍵流程:
注意:在添加外鍵時,應該根據需求設置,例如右邊紅框中的Foreign Key Options,默認在Delete時是NO ACTION,說明在刪除一個用戶時,若是數據庫中存在該用戶的文章,那麼就沒法刪除該用戶,也沒法刪除該用戶的全部文章,而若是將該選項改成CASCADE,那麼刪除該用戶,就會同時刪除該用戶全部的文章。一般後者是不太可取的,由於若是發生了刪除用戶的誤操做,頗有可能該用戶的內容被連帶刪除,且不可逆,這也是實現真實系統時須要考慮的緣由之一。
對於此前所接觸的一些經常使用的框架中,一張數據表每每對應一個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"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0"> <persistence-unit name="NewPersistenceUnit"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <properties> <property name="hibernate.connection.url" value=""/> <property name="hibernate.connection.driver_class" value=""/> <property name="hibernate.connection.username" value=""/> <property name="hibernate.connection.password" value=""/> <property name="hibernate.archive.autodetection" value="class"/> <property name="hibernate.show_sql" value="true"/> <property name="hibernate.format_sql" value="true"/> <property name="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 class BlogEntity { private int id; private String title; private String content; private Date pubDate; private UserEntity userByUserId; @Id @Column(name = "id", nullable = false) public int getId() { return id; } public void setId(int id) { this.id = id; } @Basic @Column(name = "title", nullable = false, length = 100) public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } @Basic @Column(name = "content", nullable = true, length = 255) public String getContent() { return content; } public void setContent(String content) { this.content = content; } @Basic @Column(name = "pub_date", nullable = false) public Date getPubDate() { return pubDate; } public void setPubDate(Date pubDate) { this.pubDate = pubDate; } @Override public boolean equals(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 != null) return false; if (content != null ? !content.equals(that.content) : that.content != null) return false; if (pubDate != null ? !pubDate.equals(that.pubDate) : that.pubDate != null) return false; return true; } @Override public int hashCode() { 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; } public void setUserByUserId(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 class UserEntity { 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) public int getId() { return id; } public void setId(int id) { this.id = id; } @Basic @Column(name = "nickname", nullable = false, length = 45) public String getNickname() { return nickname; } public void setNickname(String nickname) { this.nickname = nickname; } @Basic @Column(name = "password", nullable = false, length = 45) public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Basic @Column(name = "first_name", nullable = true, length = 45) public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } @Basic @Column(name = "last_name", nullable = true, length = 45) public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } @Override public boolean equals(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 != null) return false; if (password != null ? !password.equals(that.password) : that.password != null) return false; if (firstName != null ? !firstName.equals(that.firstName) : that.firstName != null) return false; if (lastName != null ? !lastName.equals(that.lastName) : that.lastName != null) return false; return true; } @Override public int hashCode() { 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; } public void setBlogsById(Collection<BlogEntity> blogsById) { this.blogsById = blogsById; } }
既然數據庫已經導入了,那麼前期準備工做基本完成,還須要進行最終的配置。
首先,打開mvc-dispatcher-servlet.xml,添加下列配置(若是某些地方報錯,請選中並按Alt + Insert補全配置):
<!-- 表示JPA Repository所在的包 --> <jpa:repositories base-package="com.gaussic.repository"/> <!-- 連接到persistence.xml --> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> <property name="persistenceUnitName" value="defaultPersistenceUnit"/> </bean> <!-- 事務管理 --> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"/> </bean> <!-- 開啓事務管理註解 --> <tx:annotation-driven transaction-manager="transactionManager"/>
講解:
(1) jpa:repositories:這一部分涉及到數據庫的接口,將在後面詳解;
(2)entityManagerFactory:實體管理器工廠,讀取persistence.xml配置;
(3)transactionManager:事務管理器,利用entityManager進行事務管理;
(4)tx:annotation-driven:打開事務管理器的註解驅動,可使用註解的方法操縱數據庫。
總體以下所示:
<?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: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-scan base-package="com.gaussic.controller"/> <!-- 靜態資源(js、image等)的訪問 --> <mvc:default-servlet-handler/> <!-- 開啓註解 --> <mvc:annotation-driven/> <!--ViewResolver 視圖解析器--> <!--用於支持Servlet、JSP視圖解析--> <bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> <property name="prefix" value="/WEB-INF/pages/"/> <property name="suffix" value=".jsp"/> </bean> <!-- 表示JPA Repository所在的包 --> <jpa:repositories base-package="com.gaussic.repository"/> <!-- 連接到persistence.xml --> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> <property name="persistenceUnitName" value="defaultPersistenceUnit"/> </bean> <!-- 事務管理 --> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"/> </bean> <!-- 開啓事務管理註解 --> <tx:annotation-driven transaction-manager="transactionManager"/> </beans>
下面,填充persistence.xml,將persistence-unit的name改成 defaultPersistenceUnit。在下面的文件中,我添加了一些更爲詳細的配置:
<?xml version="1.0" encoding="UTF-8"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0"> <persistence-unit name="defaultPersistenceUnit" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <properties> <!-- 使用MySQL方言 --> <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/> <!-- 數據庫鏈接的URL地址 --> <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/springdemo"/> <!-- 數據庫鏈接的驅動 --> <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/> <!-- 數據庫鏈接的用戶名 --> <property name="hibernate.connection.username" value="root"/> <!-- 數據庫鏈接的密碼 --> <property name="hibernate.connection.password" value="111111"/> <!-- 顯示SQL語句 --> <property name="hibernate.show_sql" value="true"/> <property name="hibernate.connection.useUnicode" value="true"/> <property name="hibernate.connection.characterEncoding" value="UTF-8"/> <!-- 在顯示SQL語句時格式化語句 --> <property name="hibernate.format_sql" value="true"/> <property name="hibernate.use_sql_comments" value="false"/> <!-- 自動輸出schema建立DDL語句 --> <property name="hibernate.hbm2ddl.auto" value="update"/> <!-- 數據庫鏈接超時後自動重連 --> <property name="hibernate.connection.autoReconnect" value="true"/> <property name="connection.autoReconnectForPools" value="true"/> <property name="connection.is-connection-validation-required" value="true"/> </properties> </persistence-unit> </persistence>
如今,從新啓動tomcat,若是沒有報錯,說明數據庫已經配置完成了,接下來就要講解數據庫的相關開發工做。
閱讀評論發現許多同窗的persistence.xml出現了問題,由於出現問題的緣由可能有不少,若是沒有徹底的報錯以及代碼的話,我這邊很難解決問題,一個辦法就是在GitHub Issues上面提問並貼出代碼,我這邊儘可能解答。另外一個辦法就是下載最新的代碼運行看有沒有什麼問題。
最後一個辦法,嘗試另一種配置方法,無需persistence.xml,直接在mvc-dispatcher-servlet.xml中配置數據庫,以下所示:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="persistenceUnitName" value="defaultPersistenceUnit"/> <property name="packagesToScan" value="com.gaussic.model" /> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/> </property> <property name="jpaProperties"> <props> <prop key="hibernate.connection.driver_class">com.mysql.jdbc.Driver</prop> <prop key="hibernate.connection.url">jdbc:mysql://localhost:3306/springdemo?useSSL=false</prop> <prop key="hibernate.connection.username">root</prop> <prop key="hibernate.connection.password">111111</prop> <prop key="hibernate.show_sql">false</prop> <prop key="hibernate.connection.useUnicode">true</prop> <prop key="hibernate.connection.characterEncoding">UTF-8</prop> <prop key="hibernate.format_sql">true</prop> <prop key="hibernate.use_sql_comments">true</prop> <prop key="hibernate.hbm2ddl.auto">update</prop> <prop key="hibernate.connection.autoReconnect">true</prop> <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop> <prop key="connection.autoReconnectForPools">true</prop> <prop key="connection.is-connection-validation-required">true</prop> <prop key="hibernate.c3p0.validate">true</prop> <prop key="hibernate.connection.provider_class">org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider</prop> <prop key="hibernate.c3p0.min_size">5</prop> <prop key="hibernate.c3p0.max_size">600</prop> <prop key="hibernate.c3p0.timeout">1800</prop> <prop key="hibernate.c3p0.max_statements">50</prop> <prop key="hibernate.c3p0.preferredTestQuery">SELECT 1;</prop> <prop key="hibernate.c3p0.testConnectionOnCheckout">true</prop> <prop key="hibernate.c3p0.idle_test_period">3000</prop> </props> </property> </bean>
刪除persistence.xml,直接修改entityManagerFactory bean爲如上圖所示。這個方法能夠擺脫persistence.xml的困擾,可是有一個小小的問題,若是以前沒有添加Java EE Persistence這個框架的,文中的Persistence工具欄將不會顯示。一個解決辦法就是,先修改mvc-dispatcher-servlet,而後再添加Java EE Persistence框架,等可以看到Persistence工具欄後,刪除persistence.xml,餘下的步驟能夠繼續操做。
轉載請註明出處:Gaussic(一個致力於AI研究卻不得不兼顧項目的研究生)。