您的位置:首页 > 其它

Hibernate 经验使用总结

2013-11-22 11:06 253 查看
此前,本博中,已有几篇文章对Hibernate技术进行了介绍,Hibernate技术知识点总结, Hibernate配置文件hibernate.cfg.xml文件详解
今天继续从实践中出发,在实践中遇到的问题,记录在此!

(1) 使用Hibernate的一定要引入SLF4J.jar Logger, 来看看它是什么,以及怎么使用,首先看一个异常:

log4j:WARN No appenders could be found for logger (com.car.common.util.PropertiesFile).
log4j:WARN Please initialize the log4j system properly.

SLF4J: slf4j-api 1.6.x (or later) is incompatible with this binding.
SLF4J: Your binding is version 1.5.5 or earlier.
SLF4J: Upgrade your binding to version 1.6.x. or 2.0.x
首先SLF4J:  The Simple Logging Facade for Java (SLF4J) serves as a simple facade or abstraction for various logging frameworks (e.g. java.util.logging, logback,
log4j) allowing the end user to plug in the desired logging framework at deployment time. 通过名称不难看出,这个SLF4J使用Facade设计模式, SLF4J的使用Mannual ,简单的说来,使用SLF4J是需要将slf4j-api-1.7.5.jar和slf4j-simple-1.7.5.jar导入CLass
Path即可,但是它有一个功能binding, 来支持其他的log Jar,比如log4j, 根据log4j的版本,选择对应的binding包,slf4j-log4j12-1.7.5.jar
和log4j.jar放入class
Path.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

但是:

SLF4J is only a facade, meaning that it does not provide a complete logging solution. Operations such as configuring
appenders or setting logging levels cannot be performed with SLF4J. Thus, at some point in time, any non-trivial application will need to directly invoke the underlying logging system. In other words, complete independence from the API underlying logging system
is not possible for a stand-alone application. Nevertheless, SLF4J reduces the impact of this dependence to near-painless levels.

所以SLF4J是用于Logger迁移用的,而不是真正的logger。真正的logger有log4j, 所以要使用logger必须使用一个真正的logger,本项目使用log4j.jar. 

SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/D:/MyProject/CarMgt/lib/slf4j-log4j12.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/D:/MyProject/CarMgt/lib/slf4j-simple-1.7.5.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: slf4j-api 1.6.x (or later) is incompatible with this binding.
SLF4J: Your binding is version 1.5.5 or earlier.
SLF4J: Upgrade your binding to version 1.6.x.
上面遇到的ERROR是Multiple Bindings,有log4j和simple的绑定,去掉simple的即可。另外关于incompatible bindings的异常,是因为本项目中使用的slf4j-api 1.6.x,而用的Hibernate版本与slf4j不符合:Hibernate3.3.2版本应该与slf4j-1.5.8版本搭配使用。

最后关于引入Hibernate后,如何快速使用Logger的步骤:

根据HIbernate的版本,使用相应的SLF4J,如 slf4j-api-1.5.8, 并将添加到Build Path
在所有代码中使用Logger的地方,都使用SLF4J的接口,如final Logger logger = LoggerFactory.getLogger(className.class); 并import org.slf4j.Logger 和 org.slf4j.LoggerFactory,即可,不要在使用log4j的接口
将具体的logger和相应的slf4j-longger也添加到Build Path,如log4j-1.2.15 和 slf4j-log4j12-1.5.8, SLF4J就会自动绑定这个真正的Logger了
使用Logger的配置文件,即可进行对Logger行为的配置,如Logger的Level,是否使用File还是console输出log.

(2)使用 hibernate tools 进行建立表结构
hbm文件与 类之间的映射关系 , 百科上的:Hibernate Tools 英文版Mannual,和 Hibernate
tools 入门教程

    添加Eclipse Hibernate tools插件 ,   http://download.jboss.org/jbosstools/updates/   和 http://download.jboss.org/jbosstools/updates/development

  如何改变默认Hibernate Tools自动生成的代码:

 有时候数据库的表名会有特定的标识作为开头,比如tbl_xxxx,当我们生成实例的时候,希望可以去掉tbl_。这时我们需要重写hibernate-tool.jar包中的DefaultReverseEngineeringStrategy方法:

 

package hibernatetools;

import org.hibernate.cfg.reveng.DefaultReverseEngineeringStrategy;
import org.hibernate.cfg.reveng.ReverseEngineeringSettings;
import org.hibernate.cfg.reveng.ReverseEngineeringStrategy;
import org.hibernate.cfg.reveng.TableIdentifier;
import org.hibernate.util.StringHelper;

public class CustomReverseEngineeringStrategy extends
DefaultReverseEngineeringStrategy {

public CustomReverseEngineeringStrategy(ReverseEngineeringStrategy delegate) {
super();
}
public CustomReverseEngineeringStrategy(){
}
private ReverseEngineeringSettings settings;
@Override
public String tableToClassName(TableIdentifier table) {
String tableName = table.getName();
if (tableName != null && tableName.toUpperCase().startsWith("TBL_")) {
String pkgName = settings.getDefaultPackageName();
int lastIndex = tableName.indexOf("_");
tableName = tableName.substring(lastIndex + 1);
String className = toUpperCamelCase(tableName);
if (pkgName.length() > 0)
return StringHelper.qualify(pkgName, className);
return className;
} else {
return super.tableToClassName(table);
}
};
public void setSettings(ReverseEngineeringSettings settings) {
super.setSettings(settings);
this.settings = settings;
}
}


  在输出设置中,reveng strategy这一项选择这个子类。

 

  在生成出来的代码中,我们也许需要自定义一些内容。这时我们需要修改hibernate-tools的输出模版,解压hibernate-tools.jar文件,找到daoTemplate这个中文件,里面的包含了所有的模版文件,可按照需求进行修改,修改完成后,在输入设置中,勾选user custom templates,在下面的Template directory中选择修改后的daoTemplate这个文件夹。
  自动生成的dao只是实现类,没有接口,且文件结尾为Home并非我们需要的DaoImpl。这种情况下我们提供两种思路: (1)修改hibernate-tools源码,修改完成后打成jar包,覆盖hibernate-tools插件所在文件目录下的文件。(2)使用自定义模版,做两套dao的模版,一个是接口,一个是实现类,互相替换,生成两次dao;命名方面可写一个简单的java程序批量修改文件名。
  生成出来的实例在一对多的情况下,属性没有泛型。这是因为我们在输出设置中没有勾选User Java 5 syntax。

hibernate提供了saveOrUpdate的方法来进行数据库的操作。hibernate会根据对象的状态决定是insert还是update,其根本是通过xml文件中unsaved-value来确定的。如果设置null,系统会根据传入的对象的id的值判断,如果是null,则表示对象不存在,那么insert;如果不是Null,则表示已经存在,那么update.如果设置为none,那么表示对象不存在,会始终调用insert;如果设置为any,那么表示对象始终存在,会始终调用update。

<id name="id" type="string" unsaved-value="null">
<column name="cid" sql-type="char(32)" not-null="true" />
<generator class="uuid.hex" />
</id>


下面的query的关于时间方面如果使用q.setDate,则插入到数据库中后就丧失了时分秒,使用q.setTimesstamp则保留,注意!

public boolean GeneralTaskRemindUpd(int generalTaskId, int rmdStatusId,
Date expectRemindDate) throws RemoteException {
boolean flag = false;
try {

Date UpdateTs = DateUtils.GetcurrentTimestamp();
String hql = "update GeneralTask set recFlag=:recFlag ,updateTs=:UpdateTs ,expectRemindDate =:expectRemindDate ,rmdStatusId =:rmdStatusId where generalTaskId=:generalTaskId";
Query q = getSession().createQuery(hql);
q.setInteger("recFlag", UPD);
q.setTimestamp("UpdateTs", UpdateTs);
q.setTimestamp("expectRemindDate", expectRemindDate);
q.setParameter("rmdStatusId", rmdStatusId);
q.setInteger("generalTaskId", generalTaskId);

log.debug("GeneralTask UpdateDate:" + UpdateTs + ", RemindDate:"
+ expectRemindDate);

ServerSerivces.updateDate(RmiUtil.GeneralTaskDao, UpdateTs);
Transaction trans = getSession().beginTransaction();
q.executeUpdate();
trans.commit();
flag = true;
} catch (HibernateException e) {
log.error("", e);
} finally {

}
return flag;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息