最近在學hibernate,常見的教程都是搭配mysql,因為公司本地電腦用的是pg,所以就嘗試著做個pg的小demo. 自己也是邊學邊寫,只當是加深印象.話不多說,直接開始; 一) 準備工作; 1) 本地安裝postgresql ,這個不多說,自己去網上下載; 註: 本次使用的為pg 9.4 2) ...
最近在學hibernate,常見的教程都是搭配mysql,因為公司本地電腦用的是pg,所以就嘗試著做個pg的小demo. 自己也是邊學邊寫,只當是加深印象.話不多說,直接開始;
一) 準備工作;
1) 本地安裝postgresql ,這個不多說,自己去網上下載;
註: 本次使用的為pg 9.4
2)下載pg的jdbc Driver;
網址: 可FQ的點此下載 ,不能FQ的自己百度吧。
說明一下,支持pg9.4的有4個版本,根據自己的jdk做選擇:
JDBC3 Postgresql Driver, Version 9.3-1103 ( < jdk1.6)
JDBC4 Postgresql Driver, Version 9.4.1212 ( = jdk1.6)
JDBC41 Postgresql Driver, Version 9.4.1212 (= jdk1.7)
JDBC42 Postgresql Driver, Version 9.4.1212 (= jdk1.8)
3) 下載hibernate的jar包;
網址:FQ下載 (文件還挺大,248M);既然是學習,那就直接上最新版本: 5.2.4.Final(2016-10-26)
解壓後目錄:
required目錄下的jar包是必須添加的( 比3.x版本的多了好多呀):
意外發現在spatial目錄下已經包含有pg的驅動文件了,哈哈,考慮的果然周到:
二) 啟程;
1) pg 創建一個用戶反饋表(feedback);
orm框架連接資料庫都有兩種方式:code first和db first; db first 指提前建好資料庫表格,在code中寫好匹配的model類進行mapping,而code first指在代碼中配置好表格的相關欄位信息,項目運行時,再由框架根據你的model類及配置,自動在資料庫執行表格的創建及修改操作;
如果你用db first的方式,可以用類似如下的sql語句在pg提前創建表格:
create table feedback ( id serial not null primary key, //serial 相當於mysql中的int auto_increment,實現的是自增長效果 username varchar(45) not null, content varchar(200) not null, sendtime timestamp not null )
2)創建數據表Feedback對應的持久化類Feedback, 及持久化類Feedback對應的映射文件Feedback.hbm.xml。需要註意的是,該映射文件與對應的持久化類應該在同一目錄下。關鍵代碼如下:
/** * Created by c-yangx on 11/16/2016. */ public class Feedback { private Integer id; private String username; private String content; private Timestamp sendTime; public Integer getId() { return id;} public void setId(Integer id) {this.id = id;} public String getUsername() {return username;} public void setUsername(String username) {this.username = username;} public String getContent() {return content;} public void setContent(String content) {this.content = content;} public Timestamp getSendTime() {return sendTime;} public void setSendTime(Timestamp sendTime) {this.sendTime = sendTime;} }Feedback.java
<?xml version="1.0"?> <!-- ~ Hibernate, Relational Persistence for Idiomatic Java ~ ~ License: GNU Lesser General Public License (LGPL), version 2.1 or later. ~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. --> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="models"> <class name="models.Feedback" table="feedback" catalog="hbstudy"> <id name="id" column="id" type="java.lang.Integer"> <generator class="increment"></generator> </id> <property name="username" type="java.lang.String"> <column name="username" length="45" not-null="true"> <comment>反饋人</comment> </column> </property> <property name="content" type="java.lang.String"> <column name="content" length="200" not-null="true"> <comment>反饋內容</comment> </column> </property> <property name="sendTime" type="java.sql.Timestamp"> <column name="sendTime" length="19" not-null="false"> <comment>反饋時間</comment> </column> </property> </class> </hibernate-mapping>Feedback.hbm.xml
3) 創建Hibernate的主配置文件src/hibernate.cfg.xml,該文件中存放著 資料庫連接驅動程式類、登陸資料庫的用戶名/密碼、映射實體類配置文件的位置...etc.
Hibernate在初始化時,會自動在classes路徑下尋找該主配置文件,並且讀取配置信息,用於後期的資料庫操作;
那麼問題就來了,hinernate.cfg.xml的格式是什麼呢?不要怕,你能想到的,官方也都考慮到了,直接在文件路徑下搜索,ctrl+C=>ctrl+V 就是這麼簡單;
打開文件如下,自己修改配置:
<?xml version='1.0' encoding='UTF-8'?> <!-- ~ Hibernate, Relational Persistence for Idiomatic Java ~ ~ License: GNU Lesser General Public License (LGPL), version 2.1 or later. ~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. --> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="hibernate.dialect">org.hibernate.dialect.HSQLDialect</property> <property name="hibernate.connection.driver_class">org.hsqldb.jdbcDriver</property> <property name="hibernate.connection.username">sa</property> <property name="hibernate.connection.password"></property> <property name="hibernate.connection.url">jdbc:hsqldb:.</property> <property name="hibernate.cache.use_query_cache">true</property> <property name="hibernate.cache.region_prefix">hibernate.test</property> <property name="hibernate.jdbc.use_streams_for_binary">true</property> <property name="hibernate.jdbc.batch_size">0</property> <property name="hibernate.max_fetch_depth">3</property> <!-- 是否自動創建資料庫表 他主要有一下幾個值:validate:當sessionFactory創建時, 自動驗證或者schema定義導入資料庫。 create:每次啟動都drop掉原來的schema,創建新的。 create-drop: 當sessionFactory明確關閉時,drop掉schema。update(常用):如果沒有schema就創建,有就更新。 --> <!--此處配置來實現code first--> <property name="hibernate.hbm2ddl.auto">create-drop</property> <property name="hibernate.generate_statistics">true</property> <property name="hibernate.cache.region.factory_class">org.hibernate.testing.cache.CachingRegionFactory</property> <mapping class="org.hibernate.jpa.test.Item"/> <mapping class="org.hibernate.jpa.test.Cat"/> <mapping class="org.hibernate.jpa.test.Kitten"/> <mapping class="org.hibernate.jpa.test.Distributor"/> <class-cache class="org.hibernate.jpa.test.Item" usage="read-write"/> <collection-cache collection="org.hibernate.jpa.test.Item.distributors" usage="read-write" region="RegionName"/> </session-factory> </hibernate-configuration>
4)編寫HibernateUtil.java,用於構建SessionFactory
package utils; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; /** * Created by c-yangx on 11/16/2016. */ public class HibernateUtil { static SessionFactory sessionFactory; //Init Hibernate static{ try{ Configuration config=new Configuration().configure(); sessionFactory=config.buildSessionFactory(); }catch(Exception e){ String msg=e.getMessage(); e.printStackTrace(); System.out.println(msg); } } //Start Session public static Session openSession(){ return sessionFactory.openSession(); } }HibernateUtil.java
資料庫Feedback表的操作類FeedbackDaoImpl及介面IFeedbackDao定義:
package IDao; import models.Feedback; /** * Created by c-yangx on 11/16/2016. */ public interface IFeedbackDao { void save(Feedback item); }IFeedbackDao
package dao; import IDao.IFeedbackDao; import models.Feedback; import org.hibernate.Session; import org.hibernate.Transaction; import utils.HibernateUtil; /** * Created by c-yangx on 11/16/2016. */ public class FeedbackDaoImpl implements IFeedbackDao { @Override public void save(Feedback item) { Session session=null; Transaction tx=null; try{ session= HibernateUtil.openSession(); tx=session.beginTransaction(); session.save(item); tx.commit(); }catch(Exception e){ tx.rollback(); e.printStackTrace(); throw new RuntimeException(e); }finally { session.close(); } } }FeedbackDaoImpl.java
5)最後寫一個測試類Test
import dao.FeedbackDaoImpl; import models.Feedback; import java.sql.Timestamp; /** * Created by c-yangx on 11/16/2016. */ public class Test { @org.junit.Test public void testSave(){ Feedback newItem=new Feedback(); newItem.setUsername("Andrew"); newItem.setContent("test content one"); newItem.setSendTime(new Timestamp(System.currentTimeMillis())); FeedbackDaoImpl feedbackDao=new FeedbackDaoImpl(); feedbackDao.save(newItem); } }Test
三)路途坎坷;
項目啟動運行,遇到一些bug,一起做個記錄:
a)Error msg如下; 是配置的密碼有誤,乾脆給資料庫加了一個新的role和密碼
org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment] at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:267) at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:231) at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:210) at org.hibernate.engine.jdbc.internal.JdbcServicesImpl.configure(JdbcServicesImpl.java:51) at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.configureService(StandardServiceRegistryImpl.java:94) at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:240) at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:210) at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.handleTypes(MetadataBuildingProcess.java:352) at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:111) at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.build(MetadataBuildingProcess.java:83) at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:418) at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:87) at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:691) at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:726) at utils.HibernateUtil.<clinit>(HibernateUtil.java:17) at dao.FeedbackDaoImpl.save(FeedbackDaoImpl.java:18) at Test.testSave(Test.java:19) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) at org.junit.runners.ParentRunner.run(ParentRunner.java:309) at org.junit.runner.JUnitCore.run(JUnitCore.java:160) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:117) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:262) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:84) Caused by: org.hibernate.exception.JDBCConnectionException: Error calling Driver#connect at org.hibernate.engine.jdbc.connections.internal.BasicConnectionCreator$1$1.convert(BasicConnectionCreator.java:105) at org.hibernate.engine.jdbc.connections.internal.BasicConnectionCreator.convertSqlException(BasicConnectionCreator.java:123) at org.hibernate.engine.jdbc.connections.internal.DriverConnectionCreator.makeConnection(DriverConnectionCreator.java:41) at org.hibernate.engine.jdbc.connections.internal.BasicConnectionCreator.createConnection(BasicConnectionCreator.java:58) at org.hibernate.engine.jdbc.connections.internal.PooledConnections.addConnections(PooledConnections.java:123) at org.hibernate.engine.jdbc.connections.internal.PooledConnections.<init>(PooledConnections.java:42) at org.hibernate.engine.jdbc.connections.internal.PooledConnections.<init>(PooledConnections.java:20) at org.hibernate.engine.jdbc.connections.internal.PooledConnections$Builder.build(PooledConnections.java:161) at org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl.buildPool(DriverManagerConnectionProviderImpl.java:109) at org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl.configure(DriverManagerConnectionProviderImpl.java:72) at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.configureService(StandardServiceRegistryImpl.java:94) at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:240) at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:210) at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.buildJdbcConnectionAccess(JdbcEnvironmentInitiator.java:145) at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:66) at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:35) at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:88) at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:257) ... 38 more Caused by: org.postgresql.util.PSQLException: FATAL: password authentication failed for user "postgres" at org.postgresql.core.v3.ConnectionFactoryImpl.doAuthentication(ConnectionFactoryImpl.java:443) at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:217) at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:52) at org.postgresql.jdbc.PgConnection.<init>(PgConnection.java:216) at org.postgresql.Driver.makeConnection(Driver.java:404) at org.postgresql.Driver.connect(Driver.java:272) at org.hibernate.engine.jdbc.connections.internal.DriverConnectionCreator.makeConnection(DriverConnectionCreator.java:38) ... 53 more
b)添加賬號之後,又遇到新的Bug,原來是忘了給賬號配置資料庫許可權了,在pg端配置一下就ok了
org.hibernate.exception.SQLGrammarException: could not extract ResultSet
at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:106)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:111)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:97)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:79)
at org.hibernate.id.IncrementGenerator.initializePreviousValueHolder(IncrementGenerator.java:113)
at org.hibernate.id.IncrementGenerator.generate(IncrementGenerator.java:52)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:105)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:192)
at org.hibernate.event.internal.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:38)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:177)
at org.hibernate.event.internal.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:32)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:73)
at org.hibernate.internal.SessionImpl.fireSave(SessionImpl.java:674)
at org.hibernate.internal.SessionImpl.save(SessionImpl.java:666)
at org.hibernate.internal.SessionImpl.save(SessionImpl.java:661)
at dao.FeedbackDaoImpl.save(FeedbackDaoImpl.java:20)
at Test.testSave(Test.java:18)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:262)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:84)
Caused by: org.postgresql.util.PSQLException: ERROR: permission denied for relation feedback
... 35 more
四) 抵達;
運行Test.java中的testSave方法,執行成功,再查看下資料庫,數據也已成功插入;
最後放一個項目結構圖:(說明一下,因為後續打算學習全部的ssh,所以用了個web項目)
後言:
樓主也是剛開始學習java中的ssh框架,所以後面也會繼續寫一些hibernate的crud,Spring及struct2的文章記錄自己的學習過程,併在最後整理成一個小系列.如果感興趣,歡迎大家關註;
大家有覺得可以優化的地方,也歡迎指正.
(...未完待續)
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利