??xml version="1.0" encoding="utf-8" standalone="yes"?>
Hibernate配置文g可以有两U格式,一U是 hibernate.properties Q另一U是 hibernate.cfg.xml
后者稍微方便一些,当增加hbm映射文g的时候,可以直接?hibernate.cfg.xml 里面增加Q不必像 hibernate.properties 必须在初始化代码中加入?/p>
但不怎么_两种的配|项都是一LQ下面详l介l:
在Hibernate的src目录下有一?hibernate.properties 模板Q我们不必自׃头写Q修Ҏ板就可以?)
hibernate.query.substitutions true 1, false 0, yes 'Y', no 'N'
q个配置意思是当你在Hibernate里面输入true的时候,Hibernate会{化ؓ1插入数据库,当你在Hibernate里面输入false的时候,Hibernate会{化ؓ0插入数据库,后面的YQN同理?/p>
对于某些数据库,例如Oracle来说Q没有boolean数据cdQ就是采?代表trueQ?代表falseQ因此用这个配|在Hibernate里面直接用true/false会非常直观?/p>
hibernate.dialect net.sf.hibernate.dialect.MySQLDialect
hibernate.connection.driver_class com.mysql.jdbc.Driver
hibernate.connection.url jdbc:mysql:///test
hibernate.connection.username root
hibernate.connection.password
q是一个连接MySQL数据库的例子Q很直观Q不必解释,不同的数据库的连接参数模板中全部l出了?/p>
hibernate.connection.pool_size 1
hibernate.statement_cache.size 25
q是Hibernate自带的连接池的配|参敎ͼ在默认情况下采用。意义很直观Q不多解释?/p>
只是提醒一点,Hibernateq个q接池是非常原始非常单的q接池,如果你在目中用Hibernate的话Q徏议你首选App Server的连接池Q次选Hibernate带的DBCPq接池。自带的q接池应该做为末选?/p>
如果你采用DBCPq接池,除了要配|DBCPq接池以外,q需要取消掉下行的注释:
hibernate.connection.provider_class net.sf.hibernate.connection.DBCPConnectionProvider
其它的连接池同理?/p>
如果采用App Server的连接池Q假设App Serverq接池的DataSource的JNDI名称?mypool"的话Q配|应该如下:
hibernate.dialect net.sf.hibernate.dialect.MySQLDialect
hibernate.connection.datasource mypool
hibernate.connection.provider_class net.sf.hibernate.connection.DatasourceConnectionProvider
其它参数׃必写了,因ؓ已经在App Server配置q接池的时候指定好了?/p>
如果你不是在App Server环境中用HibernateQ例如远E客LE序Q但是你又想用App Server的数据库q接池,那么你还需要配|JNDI的参敎ͼ例如Hibernateq接q程Weblogic上的数据库连接池Q?/p>
hibernate.dialect net.sf.hibernate.dialect.MySQLDialect
hibernate.connection.datasource mypool
hibernate.connection.provider_class net.sf.hibernate.connection.DatasourceConnectionProvider
hibernate.jndi.class weblogic.jndi.WLInitialContextFactory
hibernate.jndi.url t3://servername:7001/
最后,如果你需要在EJB或者JTA中用HibernateQ需要取消下行的注释Q?/p>
hibernate.transaction.factory_class net.sf.hibernate.transaction.JTATransactionFactory
杂项配置Q?/p>
hibernate.show_sql false
是否Hibernate发送给数据库的sql昄出来Q这是一个非帔R常有用处的功能。当你在调试Hibernate的时候,让Hibernate打印sql语句Q可以帮助你q速解决问题?/p>
#hibernate.connection.isolation 4
指定数据库的隔离U别Q往往不同的数据库有自己定义的隔离U别Q未必是Hibernate的设|所能更改的Q所以也不必ȝ它了?/p>
hibernate.jdbc.fetch_size 50
hibernate.jdbc.batch_size 25
q两个选项非常非常非常重要Q!Q将严重影响Hibernate的CRUD性能!
C = create, R = read, U = update, D = delete
Fetch Size 是设定JDBC的Statementd数据的时候每ơ从数据库中取出的记录条数?/p>
例如一ơ查?万条记录Q对于Oracle的JDBC驱动来说Q是不会1ơ性把1万条取出来的Q而只会取出Fetch Size条数Q当U录集遍历完了这些记录以后,再去数据库取Fetch Size条数据?/p>
因此大大节省了无谓的内存消耗。当然Fetch Size讄大Q读数据库的ơ数少Q速度快QFetch Size小Q读数据库的ơ数多Q速度慢?/p>
q有点像qx我们写程序写盘文g一P讄一个BufferQ每ơ写入BufferQ等Buffer满了以后Q一ơ写入硬盘,道理相同?/p>
Oracle数据库的JDBC驱动默认的Fetch Size=10Q是一个非怿守的讑֮Q根据我的测试,当Fetch Size=50的时候,性能会提?倍之多,当Fetch Size=100Q性能q能l箋提升20%QFetch Sizel箋增大Q性能提升的就不显著了?/p>
因此我徏议用Oracle的一定要Fetch Size讑ֈ50?/p>
不过q不是所有的数据库都支持Fetch SizeҎ,例如MySQL׃支持?/p>
MySQL像我上面说的那U最坏的情况Q他L一下就?万条记录完全取出来,内存消耗会非常非常惊hQ这个情况就没有什么好办法?:(
Batch Size是设定对数据库进行批量删除,扚w更新和批量插入的时候的Ҏ大小Q有点相当于讄Buffer~冲区大的意思?/p>
Batch Size大Q批量操作的向数据库发送sql的次数越,速度p快。我做的一个测试结果是当Batch Size=0的时候,使用Hibernate对Oracle数据库删?万条记录需?5U,Batch Size = 50的时候,删除仅仅需?U!Q!
可见有多么大的性能提升Q很多h做Hibernate和JDBC的插入性能试会奇怪的发现Hibernate速度臛_是JDBC的两倍,是因ؓHibernate使用了Batch InsertQ而他们写的JDBC没有使用Batch的缘故?/p>
以我的经验来看,Oracle数据?Batch Size = 30 的时候比较合适,50也不错,性能会l提升,50以上Q性能提升的非常微弱,反而消耗内存更加多Q就没有必要了?/p>
#hibernate.jdbc.use_scrollable_resultset true
讑֮是否可以使用JDBC2.0规范的可滚动l果集,q对Hibernate的分|C有一定的作用Q默认就好了?/p>
#hibernate.cglib.use_reflection_optimizer false
默认打开Q启用cglib反射优化。cglib是用来在Hibernate中动态生成PO字节码的Q打开优化可以加快字节码构造的速度?/p>
不过Q当你在调试E序q程中,特别是和proxyQlazy loading相关的应用中Q代码出错,但是出错提示信息有语焉不详,那么你可以把cglib优化xQ这样Hibernate会输出比较详l的调试信息Q帮助你debug?/p>
Hibernate 入门 - 实战演练
本文配置环境Q?br />JBuilder X
jdk 1.4.2
Mysql 4.0.11 驱动:mm.mysql-2.0.4-bin.jar(org.gjt.mm.mysql.Driver)
Hibernate 2.1
解压Hibernate
打开JBQ新建工E,名ؓQhibernate
加入Hibernate需要的包与MYSQL驱动
步骤:file->new project->name中输入hibernate,directory选择你要存放本工E的路径->next
->required libraries->add->new->name中输入你要设|的hibernate包名
->add->选择你hibernate解压到的目录Q选中该目录下的hibernate2.jar与lib目录下的所有jar包,再把你的MYSQL驱动包也加进?/p>
然后一直按OKQnext?/p>
新徏一个类,名ؓHello_Bean.java,代码如下Q?/p>
package hibernate;
import java.io.Serializable;
public class Hello_Bean implements Serializable {
private String name;//q里name与address和id的名字可以自己定Q不会有什么媄?但get与setҎ不可以。因为那得跟数据库与配置文g对应?/p>
private String address;
private int id;
public Hello_Bean() {
}
public Hello_Bean(String name, String address) {//构造函?看完本章以后怿你会明白的了
this.name = name;
this.address = address;
}
public String getName() {//此方法名必须与Hello_Bean.hbm.xml文g里的对应的名字一P下面会详l讲
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public int getId() {//必须的方?br />return id;
}
public void setId(int id)//必须的方?br />{
this.id = id;
}
}
完成q一步以后编?/p>
hibernate解压后的目录下的src文g多w的hibernate.properties与log4j.properties文g复制C的工E目录的classes目录?/p>
(例如hibernate\classes\目录?Q?/p>
打开hibernate.properties文gQ找?/p>
## HypersonicSQL
hibernate.dialect net.sf.hibernate.dialect.HSQLDialect
hibernate.connection.driver_class org.hsqldb.jdbcDriver
hibernate.connection.username sa
hibernate.connection.password
hibernate.connection.url jdbc:hsqldb:hsql://localhost
hibernate.connection.url jdbc:hsqldb:test
hibernate.connection.url jdbc:hsqldb:.
改ؓ
## HypersonicSQL
#hibernate.dialect net.sf.hibernate.dialect.HSQLDialect
#hibernate.connection.driver_class org.hsqldb.jdbcDriver
#hibernate.connection.username sa
#hibernate.connection.password
#hibernate.connection.url jdbc:hsqldb:hsql://localhost
#hibernate.connection.url jdbc:hsqldb:test
#hibernate.connection.url jdbc:hsqldb:.
再找?/p>
## MySQL
#hibernate.dialect net.sf.hibernate.dialect.MySQLDialect
#hibernate.connection.driver_class org.gjt.mm.mysql.Driver
#hibernate.connection.driver_class com.mysql.jdbc.Driver
#hibernate.connection.url jdbc:mysql:///test
#hibernate.connection.username root
#hibernate.connection.password
改ؓ
## MySQL
hibernate.dialect net.sf.hibernate.dialect.MySQLDialect
hibernate.connection.driver_class org.gjt.mm.mysql.Driver
hibernate.connection.url jdbc:mysql://localhost:3306/test
hibernate.connection.username root
hibernate.connection.password
上面的URLhZ自己?/p>
完成以后创徏一个空的文Ӟ保存在你工程的类文g同个文g多wQ例如hibernate\classes\hibernate\目录下)Q文件名为:Hello_Bean.hbm.xml
内容如下Q?/p>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>
<class name="hibernate.Hello_Bean" table="test_hibernate" >
<id name="id" column="id">
<generator class="identity"/>
</id>
<property name="name" type="string" update="true" insert="true" column="name" />
<property name="address" type="string" update="true" insert="true" column="address" />
</class>
</hibernate-mapping>
E微解释一?<class name="hibernate.Hello_Bean" table="test_hibernate" >里的name指你的生成表的类Q?/p>
table则指定你要创建的数据库表的名字,可以自由修改Q没有媄?
<id name="id" column="id">讄主键IDQ这里name的值id跟Hello_Bean.java里的ҎgetId与setId对应Q不用管q个,hibernate会自动调用,配置好就可以了,column的gؓ要生成的字段名,可以自由修改Q没有媄响?/p>
<generator class="identity"/>属性让主键的ID自增Q插入数据的时候自动加1Q?/p>
<property name="name" type="string" update="true" insert="true" column="name" />q里的name?name"跟Hello_Bean.java里的getNameҎ对应Qcolumn生成的字D名
<property name="address" type="string" update="true" insert="true" column="address" />
分别d一个字Dname与addressQ注意这里的type属性类型ؓstring,如果q里的类型与Hello_Bean.java里设|的cd不一样会出错?/p>
修改完以后保存?/p>
最后在JB里新Z个类Q名字ؓHello.javaQ我会一步步解释Q代码如下:
package hibernate;
import net.sf.hibernate.cfg.Configuration;
import net.sf.hibernate.SessionFactory;
import net.sf.hibernate.tool.hbm2ddl.SchemaExport;
import net.sf.hibernate.Session;
import net.sf.hibernate.Query;
import net.sf.hibernate.Hibernate;
import net.sf.hibernate.type.LongType;
import net.sf.hibernate.Transaction;
import net.sf.hibernate.ScrollableResults;
import java.util.*;
public class Hello {
public Hello() {
}
public static void main(String[] args) throws Exception {
Configuration cfg = new Configuration().addClass(Hello_Bean.class);//用Hello_Bean.classcd始化
SessionFactory sessions = cfg.buildSessionFactory();//用buildSessionFactoryҎ得到一个SessionFactory对象
Session session = sessions.openSession();//再用SessionFactory的openSessionҎ得到一个session
new SchemaExport(cfg).create(true, true);//q句意思是创徏表,W一ơ运行以后,是创徏完表以后再把q行加上注释。如果徏表以后不把这一句注释掉的话会删掉以前创建的表再重新Z个?/p>
Hello_Bean my_hibernate = new Hello_Bean();//得到一个Hello_Bean对象
my_hibernate.setName("my_name");//讄Hello_Bean对象的namegؓmy_name,q里其实是说把字符串my_name当作数据库字Dname的?数据库字Dname与Hello_Beanc里的getName,setNameҎ是对应的。Ş成一个映关pR?/p>
my_hibernate.setAddress("my_address");//如上
session.save(my_hibernate);//q句很重要,my_hibernate对象写进数据库(my_hibernate对象里的name与address我们刚刚已经讄了gQ会直接把name,address的值写q数据库去)
session.flush();
session.close();
//上面是一个简单的插入数据与第一ơ运行徏表的介绍Q下面我再介l删除与修改的方?下面的代码我
//都加了注释,自己需要什么方法(删除Q修改,循环数据库的|把注释L可以了
HSQL比较单,大家看一下例子就应该明白了,q里׃讲了?br /> 遍历数据库的Ҏ有三U,分别是Query,find,iterateQQuery和findq回一个List接口Qiterateq回一个IteratorQ具体方法可以查看这些类得知?/p>
//删除数据
/*
int a=session.delete("from Hello_Bean where id=1");//如果没有扑ֈid?的数据那么返?Q如果找到返?,q?br />//里的Hello_Bean是我们的Hello_Beanc,他跟数据库表对应Q所以我们在q里是直接用Hello_Bean来代?br />//数据库表的?br />System.out.println(a);
session.flush();
session.close();
*/
//QueryҎ查询数据
/*
Hello_Bean my_hibernate = null;
Query q = session.createQuery("from Hello_Bean");
// Query q = session.createQuery("from Hello_Bean where name=?");//q里?跟JDBC的PreparedStatementҎ?br />//差不多,只不q这里的是以0开始,jdbc的是1开始?br />// q.setString(0,"my_name");
// q.setFirstResult(0);//q句话的意思是说查询结果从W几行开始列出数?br />// q.setMaxResults(3);//q句话的意思是取多条数据Q就跟SQL SERVER的TOPҎ和MYSQL的LIMIT?br />//法一L意思?br />// ScrollableResults sc=q.scroll();//得到一个ScrollableResults,可滚动的Q如果你的数据库支持游标自由Ud?br />//话可以加上,也就是说可以判断查询l果有没有|或者移动到下一行记录等{?br />// if(!sc.next())
// {
// System.out.println("没有扑ֈ你需要的数据");
// }
session.flush();//如果使用了ScrollableResults的话hq行注释?br />session.close();//如果使用了ScrollableResults的话hq行注释?br />List l=q.list();//q回一个List接口Q用来遍历结果集
for(int i=0;i<l.size();i++){
my_hibernate = (Hello_Bean) l.get(i);//从List中取得一个my_hibernate对象
System.out.println(my_hibernate.getName());//调用my_hibernate对象的getNameҎ取得数据库name字段的?br />}
*/
//findҎ查询数据
/*
Hello_Bean my_hibernate = null;
List q = session.find("from Hello_Bean");
session.flush();
session.close();
for(int i=0;i<q.size();i++)
{
my_hibernate = (Hello_Bean) q.get(i);
System.out.println(my_hibernate.getName());
}
*/
//iterateҎ查询数据
/*
Hello_Bean my_hibernate = null;
Iterator q = session.iterate("from Hello_Bean");
while(q.hasNext())
{
my_hibernate = (Hello_Bean) q.next();
System.out.println(my_hibernate.getName());
}
*/
//修改数据
/*
Query qq=session.createQuery("from Hello_Bean");
Hello_Bean my_hibernate=(Hello_Bean)session.load(Hello_Bean.class,new Integer(2));
//q里的new Integer(2)意思是修改表中id?的那一行数?必须是一个包装类的对象,如果使用int的话会出错?br />my_hibernate.setName("geezer");//把id?的那一行数据的name字段值改?geezer"
session.flush();
session.close();
*/
}
}
最后运行就可以了?/p>
如果大家有什么不清楚的,可以下蝲q篇文章的例子看看,q行一下?/p>
下蝲完以后用JB打开hibernate.jpx可以了。用之前把hibernate和MYSQL的驱动加q去Q方法如果不知道再看看本章开头部分?/p>
常见错误Q?br />Caused by: org.dom4j.DocumentException: Invalid byte 2 of 2-byte UTF-8 sequence. Nested exception: Invalid byte 2 of 2-byte UTF-8 sequence.
如果出现q行错误说明你的xml配置文g有不规范的字W,查下?/p>
net.sf.hibernate.MappingException: Error reading resource: hibernate/Hello_Bean.hbm.xml
如果出现q行错误说明你的hibernate的XML配置文g有错
net.sf.hibernate.MappingException: Resource: hibernate/Hello_Bean.hbm.xml not found
如果出现q行错误说明hibernate的XML配置文g没有扑ֈQ你应该把XML文g攑֜与你的类文g同个目录?本文中是攑֜hibernate\classes\hibernate\目录下,也就是跟Hello_Bean.classcL件一赗?/p>
net.sf.hibernate.PropertyNotFoundException: Could not find a setter for property name in class hibernate.Hello_Bean
如果出现q行错误说明你的xml文g里设|的字段名name的gHello_Bean.javac里的getXXX或setXXXҎ不一致?/p>
net.sf.hibernate.HibernateException: JDBC Driver class not found: org.gjt.mm.mysql.Driver
如果出现q行错误说明你的MYSQL驱动没有加进JB库里或者不在CLASSPATH里?/p>