??xml version="1.0" encoding="utf-8" standalone="yes"?>
先声明一下我用的框架是Spring + Hibernate + SpringMVC 数据库用的是Oracle
昨天遇到了一个特诡异的问题就是我使用Oracle序列Q把主键的计ClHibernate处理Q?
Entity
@Table(name = "BIO_STUDY")
public class Study implements Serializable{
private static final long serialVersionUID = -5932941248053882057L;
private int id;
private Project project;
private String name;
private String description;
private Set<Experiment> experiments;
@Id
@Column(name = "ID")
@SequenceGenerator(name = "BIO_STUDY_SQ",
sequenceName = "BIO_STUDY_SQ" )
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "BIO_STUDY_SQ")
public int getId() {
return id;
}
写完部v什么都没问题,可当我写了测试类q行试时发C键的初始值竟然是50Q其步长亦是50Q在同事的帮助下发现原来是Hibernate在做|@SequenceGenerator中添加两个参?span style="color: red">QallocationSize = 1, initialValue = 1Q?/span>OK。通过查找Hibernate的资料发现原来是因ؓallocationSize的默认值是50.具体请参考http://www.oracle.com/technology/global/cn/products/ias/toplink/jpa/resources/toplink-jpa-annotations.html#SequenceGenerator
只需要增加allocationSize = 1可?/span>
]]>
@JoinTable(name = "user_role",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "role_id"))
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
public void addRole(Role role) {
if (!this.roles.contains(role)) {
this.roles.add(role);
}
}
public void removeRole(Role role) {
this.roles.remove(role);
}
Role中的部分代码如下Q?br />
@ManyToMany(
cascade = {CascadeType.PERSIST, CascadeType.MERGE},
mappedBy = "roles",
targetEntity = User.class
)
public Set<User> getUsers() {
return users;
}
而测试代码承了AbstractTransactionalJUnit4SpringContextTestsQ代码如下:
@Test
public void testManyToMany() {
Role oneRole = new Role();
oneRole.setDescription("manager");
oneRole.setEnabled(true);
oneRole.setRoleName("manger");
Role twoRole = new Role();
twoRole.setDescription("waitress");
twoRole.setEnabled(true);
twoRole.setRoleName("waitress");
User user = new User();
user.setEnabled(true);
user.setPassword("jianghaiying");
user.setUsername("Jiang HaiYing");
user.addRole(oneRole);
user.addRole(twoRole);
userDAO.persist(user);
try {
userDAO.getConnection().commit();
} catch (SQLException e) {
e.printStackTrace();
}
}
q样执行以后Q打印出的信息如下:
Hibernate: insert into user (enabled, password, username) values (?, ?, ?)
Hibernate: insert into role (description, enabled, name) values (?, ?, ?)
Hibernate: insert into role (description, enabled, name) values (?, ?, ?)
q时候问题出来了Qؓ什么没有往关系表中插入数据Q?br />
其实qƈ不是代码或者配|写错误了,在正式运行代码一切正常,而是AbstractTransactionalJUnit4SpringContextTests出的|事实上多对多兌关系是由Hibernated我们l护的,而AbstractTransactionalJUnit4SpringContextTestsZ保持数据的清z又会自动回滚。如何解册个问题呢Q?br />
ҎQ?br />
只需要在testҎ上添?span style="color: #008000">@Rollback(false)Q?/span>不让它回滚,一切正怺。这时候也可以Ltry语句了?br />
Hibernate: insert into user (enabled, password, username) values (?, ?, ?)
Hibernate: insert into role (description, enabled, name) values (?, ?, ?)
Hibernate: insert into role (description, enabled, name) values (?, ?, ?)
Hibernate: insert into user_role (user_id, role_id) values (?, ?)
Hibernate: insert into user_role (user_id, role_id) values (?, ?)
]]>
hibernate.dialect 一个Hibernate Dialectcd允许Hibernate针对特定的关pL据库生成优化的SQL. 取值full.classname.of.Dialect
hibernate.show_sql 输出所有SQL语句到控制台. 有一个另外的选择是把org.hibernate.SQLq个log category设ؓdebug?eg.true | false
hibernate.format_sql 在log和console中打印出更漂亮的SQL?取值true | false
hibernate.default_schema 在生成的SQL? 给定的schema/tablespace附加于非全限定名的表名上. 取值SCHEMA_NAME
hibernate.default_catalog 在生成的SQL? 给定的catalog附加于非全限定名的表名上. 取值CATALOG_NAME
hibernate.session_factory_name SessionFactory 创徏后,自动用这个名字绑定到JNDI? 取值jndi/composite/name
hibernate.max_fetch_depth 为单向关?一对一, 多对一)的外q接抓取Qouter join fetchQ树讄最大深? gؓ0意味着关闭默认的外连接抓? 取???之间取?nbsp;
hibernate.default_batch_fetch_size 为Hibernate兌的批量抓取设|默认数? 取?的取gؓ4, 8, ?6
hibernate.default_entity_mode 为由q个SessionFactory打开的所有Session指定默认的实体表现模? 取值dynamic-map, dom4j, pojo
hibernate.order_updates 强制Hibernate按照被更新数据的主键QؓSQL更新排序。这么做减在高ƈ发系l中事务的死锁?取值true | false
hibernate.generate_statistics 如果开? Hibernate收集有助于性能调节的统计数? 取值true | false
hibernate.use_identifer_rollback 如果开? 在对象被删除时生成的标识属性将被重设ؓ默认? 取值true | false
hibernate.use_sql_comments 如果开? Hibernate在SQL中生成有助于调试的注释信? 默认gؓfalse. 取值true | false
?3.4. Hibernate JDBC和连?connection)属?/p>
属性名 用?nbsp;
hibernate.jdbc.fetch_size 非零|指定JDBC抓取数量的大?(调用Statement.setFetchSize()).
hibernate.jdbc.batch_size 非零|允许Hibernate使用JDBC2的批量更? 取???0之间的?nbsp;
hibernate.jdbc.batch_versioned_data 如果你想让你的JDBC驱动从executeBatch()q回正确的行计数 , 那么此属性设为true(开启这个选项通常是安全的). 同时QHibernateؓ自动版本化的数据使用扚wDML. 默认gؓfalse. eg.true | false
hibernate.jdbc.factory_class 选择一个自定义的Batcher. 多数应用E序不需要这个配|属? eg.classname.of.Batcher
hibernate.jdbc.use_scrollable_resultset 允许Hibernate使用JDBC2的可滚动l果? 只有在用用h供的JDBCq接Ӟq个选项才是必要? 否则Hibernate会用连接的元数? 取值true | false
hibernate.jdbc.use_streams_for_binary 在JDBCdbinary (二进?或serializable (可序列化) 的类型时使用?stream)(pȝU属?. 取值true | false
hibernate.jdbc.use_get_generated_keys 在数据插入数据库之后Q允怋用JDBC3 PreparedStatement.getGeneratedKeys() 来获取数据库生成的key(?。需要JDBC3+驱动和JRE1.4+, 如果你的数据库驱动在使用Hibernate的标 识生成器旉到问题,请将此D为false. 默认情况下将使用q接的元数据来判定驱动的能力. 取值true|false
hibernate.connection.provider_class 自定义ConnectionProvider的类? 此类用来向Hibernate提供JDBCq接. 取值classname.of.ConnectionProvider
hibernate.connection.isolation 讄JDBC事务隔离U别. 查看java.sql.Connection来了解各个值的具体意义, 但请注意多数数据库都不支持所有的隔离U别. 取?, 2, 4, 8
hibernate.connection.autocommit 允许被缓存的JDBCq接开启自动提?autocommit) (不徏?. 取值true | false
hibernate.connection.release_mode 指定Hibernate在何旉放JDBCq接. 默认情况?直到Session被显式关闭或被断开q接?才会释放JDBCq接. 对于应用E序服务器的JTA数据? 你应当用after_statement, q样在每ơJDBC调用后,都会d的释放连? 对于非JTA的连? 使用after_transaction在每个事务结束时释放q接是合理的. autoؓJTA和CMT事务{略选择after_statement, 为JDBC事务{略选择after_transaction. 取值on_close | after_transaction | after_statement | auto
hibernate.connection.<propertyName> JDBC属性propertyName传递到DriverManager.getConnection()中去.
hibernate.jndi.<propertyName> 属性propertyName传递到JNDI InitialContextFactory中去.
?3.5. Hibernate~存属?/p>
属性名 用?nbsp;
hibernate.cache.provider_class 自定义的CacheProvider的类? 取值classname.of.CacheProvider
hibernate.cache.use_minimal_puts 以频J的L作ؓ代h, 优化二~存来最化写操? 在Hibernate3中,q个讄对的集群~存非常有用, 寚w缓存的实现而言Q默认是开启的. 取值true|false
hibernate.cache.use_query_cache 允许查询~存, 个别查询仍然需要被讄为可~存? 取值true|false
hibernate.cache.use_second_level_cache 能用来完全禁止用二U缓? 寚w些在cȝ映射定义中指?lt;cache>的类Q会默认开启二U缓? 取值true|false
hibernate.cache.query_cache_factory 自定义实现QueryCache接口的类? 默认为内建的StandardQueryCache. 取值classname.of.QueryCache
hibernate.cache.region_prefix 二~存区域名的前缀. 取值prefix
hibernate.cache.use_structured_entries 强制Hibernate以更人性化的格式将数据存入二~存. 取值true|false
?3.6. Hibernate事务属?/p>
属性名 用?nbsp;
hibernate.transaction.factory_class 一个TransactionFactory的类? 用于Hibernate Transaction API (默认为JDBCTransactionFactory). 取值classname.of.TransactionFactory
jta.UserTransaction 一个JNDI名字Q被JTATransactionFactory用来从应用服务器获取JTA UserTransaction. 取值jndi/composite/name
hibernate.transaction.manager_lookup_class 一个TransactionManagerLookup的类?- 当用JVMU缓存,或在JTA环境中用hilo生成器的时候需要该c? 取值classname.of.TransactionManagerLookup
hibernate.transaction.flush_before_completion 如果开? session在事务完成后被自动清洗(flush)?现在更好的方法是使用自动session上下文管理。取值true | false
hibernate.transaction.auto_close_session 如果开? session在事务完成后被自动关闭?现在更好的方法是使用自动session上下文管理。取值true | false
?3.7. 其他属?/p>
属性名 用?nbsp;
hibernate.current_session_context_class ?当前" Session指定一?自定义的){略。eg.jta | thread | custom.Class
hibernate.query.factory_class 选择HQL解析器的实现. 取值org.hibernate.hql.ast.ASTQueryTranslatorFactory or org.hibernate.hql.classic.ClassicQueryTranslatorFactory
hibernate.query.substitutions Hibernate查询中的W号映射到SQL查询中的W号 (W号可能是函数名或常量名?. 取值hqlLiteral=SQL_LITERAL, hqlFunction=SQLFUNC
hibernate.hbm2ddl.auto 在SessionFactory创徏Ӟ自动查数据库l构Q或者将数据库schema的DDL导出到数据库. 使用 create-drop?在显式关闭SessionFactoryӞdrop掉数据库schema. 取值validate | update | create | create-drop
hibernate.cglib.use_reflection_optimizer 开启CGLIB来替代运行时反射机制(pȝU属?. 反射机制有时在除错时比较有用. 注意即关闭q个优化, Hibernateq是需要CGLIB. 你不能在hibernate.cfg.xml中设|此属? 取值true | false
3.4.1. SQL方言 你应当LZ的数据库hibernate.dialect属性设|成正确?org.hibernate.dialect.Dialect子类. 如果你指定一U方a, Hibernateؓ上面列出的一些属性用合理的默认? Z省去了手工指定它们的功夫.
?3.8. Hibernate SQL方言 (hibernate.dialect)
RDBMS 方言
DB2 org.hibernate.dialect.DB2Dialect
DB2 AS/400 org.hibernate.dialect.DB2400Dialect
DB2 OS390 org.hibernate.dialect.DB2390Dialect
PostgreSQL org.hibernate.dialect.PostgreSQLDialect
MySQL org.hibernate.dialect.MySQLDialect
MySQL with InnoDB org.hibernate.dialect.MySQLInnoDBDialect
MySQL with MyISAM org.hibernate.dialect.MySQLMyISAMDialect
Oracle (any version) org.hibernate.dialect.OracleDialect
Oracle 9i/10g org.hibernate.dialect.Oracle9Dialect
Sybase org.hibernate.dialect.SybaseDialect
Sybase Anywhere org.hibernate.dialect.SybaseAnywhereDialect
Microsoft SQL Server org.hibernate.dialect.SQLServerDialect
SAP DB org.hibernate.dialect.SAPDBDialect
Informix org.hibernate.dialect.InformixDialect
HypersonicSQL org.hibernate.dialect.HSQLDialect
Ingres org.hibernate.dialect.IngresDialect
Progress org.hibernate.dialect.ProgressDialect
Mckoi SQL org.hibernate.dialect.MckoiDialect
Interbase org.hibernate.dialect.InterbaseDialect
Pointbase org.hibernate.dialect.PointbaseDialect
FrontBase org.hibernate.dialect.FrontbaseDialect
Firebird org.hibernate.dialect.FirebirdDialect
?3.9. Hibernate日志cd
cd 功能
org.hibernate.SQL 在所有SQL DML语句被执行时为它们记录日?nbsp;
org.hibernate.type 为所有JDBC参数记录日志
org.hibernate.tool.hbm2ddl 在所有SQL DDL语句执行时ؓ它们记录日志
org.hibernate.pretty 在session清洗(flush)Ӟ为所有与其关联的实体(最?0?的状态记录日?nbsp;
org.hibernate.cache 为所有二U缓存的zd记录日志
org.hibernate.transaction Z务相关的zd记录日志
org.hibernate.jdbc 为所有JDBC资源的获取记录日?nbsp;
org.hibernate.hql.AST 在解析查询的时?记录HQL和SQL的AST分析日志
org.hibernate.secure 为JAAS认证h做日?nbsp;
org.hibernate ZQ何Hibernate相关信息做日?(信息量较? 但对查错非常有帮?
?3.10. JTA TransactionManagers
Transaction工厂c?nbsp; 应用E序服务?nbsp;
org.hibernate.transaction.JBossTransactionManagerLookup JBoss
org.hibernate.transaction.WeblogicTransactionManagerLookup Weblogic
org.hibernate.transaction.WebSphereTransactionManagerLookup WebSphere
org.hibernate.transaction.WebSphereExtendedJTATransactionLookup WebSphere 6
org.hibernate.transaction.OrionTransactionManagerLookup Orion
org.hibernate.transaction.ResinTransactionManagerLookup Resin
org.hibernate.transaction.JOTMTransactionManagerLookup JOTM
org.hibernate.transaction.JOnASTransactionManagerLookup JOnAS
org.hibernate.transaction.JRun4TransactionManagerLookup JRun4
org.hibernate.transaction.BESTransactionManagerLookup Borland ES
A?/span>Lifecycle?/span>Validatable
?/span>Hibernate?/span>Lifecycle接口定义如下Q?/span>
public interface Lifecycle{
/**
在实体对象执?/span>save/insert操作之前触发
**/
public boolean onSave(Session session) throws CallbackException;
/**
?/span>session.update()执行之前触发
**/
public boolean onUpdate(Session session) throws CallbackException;
/**
在实体对象执?/span>delete操作之前触发
**/
public boolean onDelete(Session session) throws CallbackException;
/**
在实体对象加载之后触?/span>
**/
public void onLoad(Session session) throws CallbackException;
}
实体对象可以实现Lifecycle接口Q来获得在持久化阶段捕获CURD事gQƈ执行相应动作的能如下所C:
public class User implements Serializable,Lifecycle{
public boolean onSave(Session s) throws CallbackException{
……
return false;
……
}
public boolean onUpdate(Session s) throws CallbackException{
……
return true;
……
}
public boolean onDelete(Session s) throws CallbackException{
……
return false;
……
}
public boolean onLoad(Session s) throws CallbackException{
……
}
}
对于onSave,onUpdate,onDeleteҎQ如果返?/span>true则意味着需要终止执行对应的操作q程。如果在q行时抛?/span>CallbackExceptionQ对应的操作也会被终止?/span>
注意在接口中对应的方法中Q不要去通过Ҏ?/span>Session参数执行持久化操作,在这些方法中Session无法正常使用Q如果必要执行一些持久化操作Q那么需要进行特D的处理Q我们将?/span>Interceptor部分详细讲解?/span>
Hibernate中还定义?/span>Validatable接口Q该接口定义如下Q?/span>
public interface Validatable{
public void validate() throws ValidationFailure;
}
Validatable接口是用来实现数据验证的Q实体类实现Validatable接口Qƈ在接口的validateҎ中实现数据验证逻辑Q以保证数据输入的合法性?/span>validateҎ会在实体对象持久化前得到调用进行数据验证,?/span>Lifecycle接口中的Ҏ不同Q?/span>Validatable.validate()Ҏ在实体生命周期中可能被多ơ调用,因此此方法应该仅限于数据合法性的验证Q而不应该实现业务逻辑的验证?/span>
B?/span>Interceptor:
以上?/span>Hibernate提供?/span>Lifecycle接口?/span>Validatable接口Q以及用方法,q两个方法定义了一U自然的回调机制Q但是如我们所见,如果惛_现对实体的回调拦截,那么相应的实体对象必d现这两个Hibernate原生接口Q这׃代码的可UL性大大下降,因ؓ此时实体cdl不再是一?/span>POJO了,Hibernate的那些天才的设计者们也已l意识到了这个问题,所以又提供?/span>Interceptor接口Qؓ持久化事件的捕获和处理提供了一个非入R性的解决ҎQ?/span>Interceptor接口通过讄注入来实现持久化事g的捕获和处理Q这是典型的IOCQ控制反转)设计思想。下面我们就讲解Interceptor接口的技术细节和使用Ҏ?/span>
Hibernate中的Interceptor接口定义如下Q?/span>
public interface Interceptor{
//对象初始化之前调用,q时实体对象刚刚被创建,各个属性还都ؓnull,如果在这个方法中修改了实体对象的数据Q那么返?/span>trueQ否则返?/span>null.
public boolean onLoad(Object entity,Serializable id,Object[] state,
String[] propertyNames,Type[] types) throws CallbackException;
//Session.flush()在进行脏数据查时Q如果发现实体对象数据已脏,p用此Ҏ
public boolean onFlushDirty(Object entity,Serializable id,Object[] state,
String[] propertyNames,Type[] types) throws CallbackException;
//实体对象被保存前调用Q如果在q个Ҏ中修改了实体对象的数据,那么q回trueQ否则返?/span>null.
public boolean onSave(Object entity,Serializable id,Object[] state,
String[] propertyNames,Type[] types) throws CallbackException;
//通过Session删除一个实体对象前调用
public boolean onDelete(Object entity,Serializable id,Object[] state,
String[] propertyNames,Type[] types) throws CallbackException;
//Session执行flush()之前调用
public boolean preFlush(Iterator entities) throws CallbackException;
//Session执行flush()之后Q所有的SQL语句都执行完毕后调用
public boolean postFlush(Iterator entities) throws CallbackException;
//当执?/span>saveOrUpdateҎ时调用,判断实体对象是否已经保存
public Boolean isUnsaved(Object entity);
//执行Session.flush()ҎӞ调用此方法判断该对象是否对象Q这提供了脏数据查的另一个回调拦截机?/span>
public int[] findDirty(Object entity,Serializable id,Object[] state,
String[] propertyNames,Type[] types) throws CallbackException;
//?/span>Session构造实体类实例前调用,如果q回null,Hibernate会按照默认方式构造实体类对象实例
public Object findDirty(Class clazz,Serializable id) throws CallbackException;
}
Intercepter不需要实体对象来实现Q而是通过开发h员定义一个实?/span>Interceptor接口的类Q然后在创徏Hibernate SessionӞ通过?/span>Interceptor对象讄q所创徏?/span>SessionQ这样通过q个Session来操作的实体对象Q就都会hҎ久化动作的回调拦截能力。在Hibernate?/span>Interceptor对象共有两种用法Q如下所qͼ
1?/span> SessionFactory.openSession(Interceptor)Qؓ每个Session实例分配一个拦?/span>InterceptorQ这个拦截接口对象,存放?/span>Session范围内,为每?/span>Session实例所专用?/span>
2?/span> Configuration.setInterceptor(Interceptor):?/span>SessionFactory实例分配一?/span>Interceptor实例Q这?/span>Interceptor实例存放?/span>SessionFactory范围内,被每?/span>Session实例所׃n?/span>
A?/span>Interceptor的典型应用:
下面我实C个利?/span>Interceptor接口实现日志数据E核的功能,所谓日志数据稽核就是针对一些关键操作进行记录,以便作ؓ业务跟踪的基依据?/span>
首先定义用于记录操作的实体:
public class AudiLog implements Serializable{
private String id;
private String user;
private String action;
private String entityName;
private String comment;
private Long logtime;
…getter/setter…
}
接下来定?/span>Interceptor接口的实现类和用于持久化操作?/span>AuditDAOc:
package com.lbs.apps.unemployment.subsidy.beforeinfoimport.util;
import net.sf.hibernate.Session;
import net.sf.hibernate.Interceptor;
import Java.io.Serializable;
import net.sf.hibernate.type.Type;
import net.sf.hibernate.HibernateException;
import Java.util.Iterator;
import Java.util.Set;
import Java.util.HashSet;
import com.neusoft.entity.User;
public class MyInterceptor implements Interceptor{
private Set insertset=new HashSet();
private Set updateset=new HashSet();
private Session session;
private String userID;
public void setSession(Session session){
this.session=session
?/span>
public void setUserID(String id){
this.userID=id;
}
public boolean onLoad(Object object, Serializable serializable,
Object[] objectArray, String[] stringArray,
Type[] typeArray) {
return false;
}
public boolean onFlushDirty(Object object, Serializable serializable,
Object[] objectArray, Object[] objectArray3,
String[] stringArray, Type[] typeArray) {
if(object instanceof User){
insertset.add(object);
}
return false;
}
public boolean onSave(Object object, Serializable serializable,
Object[] objectArray, String[] stringArray,
Type[] typeArray) {
if(object instanceof User){
updateset.add(object);
}
return false;
}
public void onDelete(Object object, Serializable serializable,
Object[] objectArray, String[] stringArray,
Type[] typeArray) {
}
public void preFlush(Iterator iterator) {
}
public void postFlush(Iterator iterator) {
try{
if(insertset.size()>0){
AuditDAO.dolog(“insert”,userID,inserset,session.connection);
}
if(updateset.size()>0){
AuditDAO.dolog(“update”,userID,updateset,session.connection);
}
}catch(HibernateException he){
he.printStackTrace();
}
}
public Boolean isUnsaved(Object object) {
return null;
}
public int[] findDirty(Object object, Serializable serializable,
Object[] objectArray, Object[] objectArray3,
String[] stringArray, Type[] typeArray) {
return null;
}
public Object instantiate(Class class0, Serializable serializable) {
return "";
}
}
public class AuditDAO{
public static void doLog(String action,String userID,Set modifySet,Connection connection){
Session tempsession=HibernateUtil.getSessionFactory().openSession(connection);
try{
Iterator it=modifyset.iterator();
while(it.hasNext()){
User user=(User)it.next();
AudiLog log=new AudiLog();
log.setUserID(userID);
log.setAction(action);
log.setComment(user.toString());
log.setLogTime(new Long(Calendar.getInstance().getTime().getTime()));
tempsession.save(log);
}
}catch(Exception e){
throw new CallbackException(e);
}finally{
try{
tempsesson.close();
}catch(HibernateException he){
throw new CallbackException(he);
}
}
}
}
最后看一下业务逻辑ȝ序:
SessionFactory sessionfactory=config.buildSessionFactory();
MyInterceptor it=new MyInterceptor();
session=sessionfactory().openSession(it);
it.setUserID(“currentUser”);
it.setSession(session);
User user=new User();
user.setName(“zx”);
Transaction tx=session.beginTransaction();
session.save(user);
tx.commit();
session.close();
以上CZ代码中,在创?/span>SessionӞ讄Interceptor实例对象Q当执行?/span>session.save(user)前,会触?/span>onSave()ҎQ当执行tx.commit()Ӟ会执?/span>flush()Q在执行该方法后会触?/span>postFlush()ҎQ这个方法通过AuditDAOq行持久化保存业务日志,在这个类中的U色部分时有x久化操作部分Q我们ƈ没有使用原有?/span>Session实例Q这是因避免Session内部状态乱,因此我们依托当前Session?/span>JDBC Connection创徏了一个?/span>Session用于保存操作记录Q在q个持久化操作中没有启动事务Q这是因Z?/span>Session中的JDBC Connection是与外围调用Interceptor?/span>Session׃n,而事务已l在外围Session?/span>JDBC Connection上启动。这是在拦截Ҏ中进行持久化操作的标准方法。MInterceptor提供了非入R性的回调拦截机制Q我们可以方便而且优雅的实C些持久化操作的特D需求?/span>
q个cM要在使用的时候当作获得数据源的标志用?
二、徏立一个获得和讄上下文的c:
此时在遍历list时就可以(Tree)list.get[i];每一行的内容变换Z个对象了?
另还可以q回一个Map对象Q也是说在在list里包含多个MapQ代码如?
Query query = session.createSQLQuery("select id,name from Tree t where pid in (select id from Tree) ").setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP); //q回一个map,KEY:为DB中名UC_大小写一_遍历list时就可以
Map map = (Map)list.get[i];
map.get("id");map.get("name");来取倹{按你的SQL语句select后的字段名来作ؓmap的KeyQ但q个key必须与数据库中的字段名一模一栗?
q可以用作函数方面的。如
Query query = session.createSQLQuery("select sum(id) SUMID from Tree t where pid in (select id from Tree)
.addScalar("SUMID",Hibernate.INTEGER) //转换cdQ按DB中的type?br />
.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP); //q回一个map,KEY:为DB中名UC_大小写一_
直接map.get("SUMID")可以取g
q有一点就是这个方法在Hibernate3.2版本上才能正常运行?
private byte[] contentQ?/span> |
注解Q?/span>
@Lob |
CLOBcdQ类型声明ؓString卛_Q?/span>
private String remarkQ?/span> |
注解Q?/span>
@Lob |
SecondaryTables
当一个entity class映射C个主表和多个从表Ӟ用SecondaryTables来定义各个从表的属性?
元数据属性说明:
· valueQ?定义一个SecondaryTable数组Q指定每个从表的属性?
@Table(name = "CUSTOMER")
@SecondaryTables( value = {
@SecondaryTable(name = "CUST_NAME", pkJoin = { @PrimaryKeyJoinColumn(name = "STMO_ID", referencedColumnName = "id") }),
@SecondaryTable(name = "CUST_ADDRESS", pkJoin = { @PrimaryKeyJoinColumn(name = "STMO_ID", referencedColumnName = "id") }) })
public class Customer {}
UniqueConstraint
UniqueConstraint定义在Table或SecondaryTable元数据里Q用来指定徏表时需要徏唯一U束的列?
元数据属性说明:
· columnNames:定义一个字W串数组Q指定要建唯一U束的列名?
@Entity
@Table(name="EMPLOYEE",
uniqueConstraints={@UniqueConstraint(columnNames={"EMP_ID", "EMP_NAME"})}
)
public class Employee { ... }
Column
Column元数据定义了映射到数据库的列的所有属性:列名Q是否唯一Q是否允ؓI,是否允许更新{?
元数据属性说明:
· name:列名?
· unique: 是否唯一
· nullable: 是否允许为空
· insertable: 是否允许插入
· updatable: 是否允许更新
· columnDefinition: 定义时创建此列的DDL
· secondaryTable: 从表名。如果此列不建在主表上(默认建在主表Q,该属性定义该列所在从表的名字?
public class Person {
@Column(name = "PERSONNAME", unique = true, nullable = false, updatable = true)
private String name;
@Column(name = "PHOTO", columnDefinition = "BLOB NOT NULL", secondaryTable="PER_PHOTO")
private byte[] picture;
JoinColumn
如果在entity class的field上定义了关系Qone2one或one2many{)Q我们通过JoinColumn来定义关pȝ属性。JoinColumn的大部分属性和ColumncM?
元数据属性说明:
· name:列名?
· referencedColumnName:该列指向列的列名Q徏表时该列作ؓ外键列指向关pd一端的指定列)
· unique: 是否唯一
· nullable: 是否允许为空
· insertable: 是否允许插入
· updatable: 是否允许更新
· columnDefinition: 定义时创建此列的DDL
· secondaryTable: 从表名。如果此列不建在主表上(默认建在主表Q,该属性定义该列所在从表的名字?
下面的代码说明Custom和Order是一对一关系。在Order对应的映表Z个名为CUST_ID的列Q该列作为外键指向Custom对应表中名ؓID的列?
public class Custom {
@OneToOne
@JoinColumn(
name="CUST_ID", referencedColumnName="ID", unique=true, nullable=true, updatable=true)
public Order getOrder() {
return order;
}
JoinColumns
如果在entity class的field上定义了关系Qone2one或one2many{)Qƈ且关pd在多个JoinColumnQ用JoinColumns定义多个JoinColumn的属性?
元数据属性说明:
· value: 定义JoinColumn数组Q指定每个JoinColumn的属性?
下面的代码说明Custom和Order是一对一关系。在Order对应的映表Z列,一列名为CUST_IDQ该列作为外键指向Custom对应表中名ؓID的列,另一列名为CUST_NAMEQ该列作为外键指向Custom对应表中名ؓNAME的列?
public class Custom {
@OneToOne
@JoinColumns({
@JoinColumn(name="CUST_ID", referencedColumnName="ID"),
@JoinColumn(name="CUST_NAME", referencedColumnName="NAME")
})
public Order getOrder() {
return order;
}
Id
声明当前field为映表中的主键列。id值的获取方式有五U:TABLE, SEQUENCE, IDENTITY, AUTO, NONE。Oracle和DB2支持SEQUENCEQSQL Server和Sybase支持IDENTITY,mysql支持AUTO。所有的数据库都可以指定为AUTOQ我们会Ҏ不同数据库做转换。NONE (默认)需要用戯己指定Id的倹{元数据属性说明:
· generate():主键值的获取cd
· generator():TableGenerator的名字(当generate=GeneratorType.TABLE才需要指定该属性)
下面的代码声明Task的主键列id是自动增长的?Oracle和DB2从默认的SEQUENCE取|SQL Server和Sybase该列建成IDENTITYQmysql该列建成auto increment?
@Entity
@Table(name = "OTASK")
public class Task {
@Id(generate = GeneratorType.AUTO)
public Integer getId() {
return id;
}
}
IdClass
当entity class使用复合主键Ӟ需要定义一个类作ؓid class。id class必须W合以下要求:cdd明ؓpublicQƈ提供一个声明ؓpublic的空构造函数。必d现Serializable接,覆写 equals()和hashCodeQ)Ҏ。entity class的所有id field在id class都要定义Q且cd一栗?
元数据属性说明:
· value: id class的类?
public class EmployeePK implements Java.io.Serializable{
String empName;
Integer empAge;
public EmployeePK(){}
public boolean equals(Object obj){ ......}
public int hashCode(){......}
}
@IdClass(value=com.acme.EmployeePK.class)
@Entity(access=FIELD)
public class Employee {
@Id String empName;
@Id Integer empAge;
}
MapKey
在一对多Q多对多关系中,我们可以用Map来保存集合对象。默认用主键值做keyQ如果用复合主键,则用id class的实例做keyQ如果指定了name属性,q指定的field的值做key?
元数据属性说明:
· name: 用来做key的field名字
下面的代码说明Person和Book之间是一对多关系。Person的books字段是MapcdQ用Book的isbn字段的g为Map的key?
@Table(name = "PERSON")
public class Person {
@OneToMany(targetEntity = Book.class, cascade = CascadeType.ALL, mappedBy = "person")
@MapKey(name = "isbn")
private Map books = new HashMap();
}
OrderBy
在一对多Q多对多关系中,有时我们希望从数据库加蝲出来的集合对象是按一定方式排序的Q这可以通过OrderBy来实玎ͼ默认是按对象的主键升序排列?
元数据属性说明:
· value: 字符串类型,指定排序方式。格式ؓ"fieldName1 [ASC|DESC],fieldName2 [ASC|DESC],......",排序cd可以不指定,默认是ASC?
下面的代码说明Person和Book之间是一对多关系。集合books按照Book的isbn升序Qname降序排列?
@Table(name = "MAPKEY_PERSON")
public class Person {
@OneToMany(targetEntity = Book.class, cascade = CascadeType.ALL, mappedBy = "person")
@OrderBy(name = "isbn ASC, name DESC")
private List books = new ArrayList();
}
PrimaryKeyJoinColumn
在三U情况下会用到PrimaryKeyJoinColumn?
· l承?
· entity class映射C个或多个从表。从表根据主表的主键列(列名为referencedColumnName值的列)Q徏立一个类型一L主键列,列名由name属性定义?
· one2one关系Q关pȝ护端的主键作为外键指向关p被l护端的主键Q不再新Z个外键列?
元数据属性说明:
· name:列名?
· referencedColumnName:该列引用列的列名
· columnDefinition: 定义时创建此列的DDL
下面的代码说明Customer映射C个表Q主表CUSTOMER,从表CUST_DETAILQ从表需要徏立主键列CUST_IDQ该列和主表的主键列id除了列名不同Q其他定义一栗?
@Entity
@Table(name="CUSTOMER")
@SecondaryTable(name="CUST_DETAIL",pkJoin=@PrimaryKeyJoinColumn(name="CUST_ID"QreferencedColumnName="id"))
public class Customer {
@Id(generate = GeneratorType.AUTO)
public Integer getId() {
return id;
}
}
下面的代码说明Employee和EmployeeInfo是一对一关系QEmployee的主键列id作ؓ外键指向EmployeeInfo的主键列INFO_ID?
@Table(name = "Employee")
public class Employee {
@OneToOne
@PrimaryKeyJoinColumn(name = "id", referencedColumnName="INFO_ID")
EmployeeInfo info;
}
PrimaryKeyJoinColumns
如果entity class使用了复合主键,指定单个PrimaryKeyJoinColumn不能满要求Ӟ可以用PrimaryKeyJoinColumns来定义多个PrimaryKeyJoinColumn?
元数据属性说明:
· value: 一个PrimaryKeyJoinColumn数组Q包含所有PrimaryKeyJoinColumn?
下面的代码说明了Employee和EmployeeInfo是一对一关系。他们都使用复合主键Q徏表时需要在Employee表徏立一个外键,从Employee的主键列id,name指向EmployeeInfo的主键列INFO_ID和INFO_NAME.
@Entity
@IdClass(EmpPK.class)
@Table(name = "EMPLOYEE")
public class Employee {
private int id;
private String name;
private String address;
@OneToOne(cascade = CascadeType.ALL)
@PrimaryKeyJoinColumns({
@PrimaryKeyJoinColumn(name="id", referencedColumnName="INFO_ID"),
@PrimaryKeyJoinColumn(name="name" , referencedColumnName="INFO_NAME")})
EmployeeInfo info;
}
@Entity
@IdClass(EmpPK.class)
@Table(name = "EMPLOYEE_INFO")
public class EmployeeInfo {
@Id
@Column(name = "INFO_ID")
private int id;
@Id
@Column(name = "INFO_NAME")
private String name;
}
Transient
Transient用来注释entity的属性,指定的这些属性不会被持久化,也不会ؓq些属性徏表?
@Transient
private String name;
Version
Version指定实体cd乐观事务中的version属性。在实体c重新由EntityManager理q且加入C观事务中Ӟ保证完整性。每一个类只能有一个属性被指定为versionQversion属性应该映到实体cȝ主表上?
下面的代码说明versionNum属性作个类的versionQ映到数据库中主表的列名是OPTLOCK?
@Version
@Column("OPTLOCK")
protected int getVersionNum() { return versionNum; }
Lob
Lob指定一个属性作为数据库支持的大对象cd在数据库中存储。用LobTypeq个枚D来定义Lob是二q制cdq是字符cd?
LobType枚Dcd说明Q?
· BLOB 二进制大对象QByte[]或者Serializable的类型可以指定ؓBLOB?
· CLOB 字符型大对象Qchar[]、Character[]或Stringcd可以指定为CLOB?
元数据属性说明:
· fetchQ?定义q个字段是lazy loadedq是eagerly fetched。数据类型是FetchType枚DQ默认ؓLAZY,即lazy loaded.
· typeQ?定义q个字段在数据库中的JDBC数据cd。数据类型是LobType枚DQ默认ؓBLOB?
下面的代码定义了一个BLOBcd的属性和一个CLOBcd的属性?
@Lob
@Column(name="PHOTO" columnDefinition="BLOB NOT NULL")
protected JPEGImage picture;
@Lob(fetch=EAGER, type=CLOB)
@Column(name="REPORT")
protected String report;
JoinTable
JoinTable在many-to-many关系的所有者一边定义。如果没有定义JoinTableQ用JoinTable的默认倹{?
元数据属性说明:
· table:q个join table的Table定义?
· joinColumns:定义指向所有者主表的外键列,数据cd是JoinColumn数组?
· inverseJoinColumns:定义指向非所有者主表的外键列,数据cd是JoinColumn数组?
下面的代码定义了一个连接表CUST和PHONE的join table。join table的表名是CUST_PHONEQ包含两个外键,一个外键是CUST_IDQ指向表CUST的主键IDQ另一个外键是PHONE_IDQ指向表PHONE的主键ID?
@JoinTable(
table=@Table(name=CUST_PHONE),
joinColumns=@JoinColumn(name="CUST_ID", referencedColumnName="ID"),
inverseJoinColumns=@JoinColumn(name="PHONE_ID", referencedColumnName="ID")
)
TableGenerator
TableGenerator定义一个主键值生成器Q在Idq个元数据的generateQTABLEӞgenerator属性中可以使用生成器的名字。生成器可以在类、方法或者属性上定义?
生成器是为多个实体类提供q箋的ID值的表,每一行ؓ一个类提供ID|ID值通常是整数?
元数据属性说明:
· name:生成器的唯一名字Q可以被Id元数据用?
· table:生成器用来存储id值的Table定义?
· pkColumnName:生成器表的主键名U?
· valueColumnName:生成器表的ID值的列名U?
· pkColumnValue:生成器表中的一行数据的主键倹{?
· initialValue:id值的初始倹{?
· allocationSize:id值的增量?
下面的代码定义了两个生成器empGen和addressGenQ生成器的表是ID_GEN?
@Entity public class Employee {
...
@TableGenerator(name="empGen",
table=@Table(name="ID_GEN"),
pkColumnName="GEN_KEY",
valueColumnName="GEN_VALUE",
pkColumnValue="EMP_ID",
allocationSize=1)
@Id(generate=TABLE, generator="empGen")
public int id;
...
}
@Entity public class Address {
...
@TableGenerator(name="addressGen",
table=@Table(name="ID_GEN"),
pkColumnValue="ADDR_ID")
@Id(generate=TABLE, generator="addressGen")
public int id;
...
}
SequenceGenerator
SequenceGenerator定义一个主键值生成器Q在Idq个元数据的generator属性中可以使用生成器的名字。生成器可以在类、方法或者属性上定义。生成器是数据库支持的sequence对象?
元数据属性说明:
· name:生成器的唯一名字Q可以被Id元数据用?
· sequenceName:数据库中Qsequence对象的名U。如果不指定Q会使用提供商指定的默认名称?
· initialValue:id值的初始倹{?
· allocationSize:id值的增量?
下面的代码定义了一个用提供商默认名称的sequence生成器?
@SequenceGenerator(name="EMP_SEQ", allocationSize=25)
DiscriminatorColumn
DiscriminatorColumn定义在用SINGLE_TABLE或JOINEDl承{略的表中区别不l承层次的列?
元数据属性说明:
· name:column的名字。默认gؓTYPE?
· columnDefinition:生成DDL的sql片断?
· length:Stringcd的column的长度,其他cd使用默认?0?
下面的代码定义了一个列名ؓDISCQ长度ؓ20的Stringcd的区别列?
@Entity
@Table(name="CUST")
@Inheritance(strategy=SINGLE_TABLE,
discriminatorType=STRING,
discriminatorValue="CUSTOMER")
@DiscriminatorColumn(name="DISC", length=20)
public class Customer { ... }
寚w要解决的问题的描qͼ
把一?span class="hilite2">enumcd的字D|久化到数据库中,写入到数据库中的gؓIntegercdQ且有特定的含义Q?br />
我们知道Q如果我们某一个pojo对象的某个属性ؓenumcd的话Q在持久化的时候可能会出现如下两种情况:
1、数据库中enum_col的类型ؓ(oracle:number或者sql server:numeric)
@Column(name="enum_col")
public MyEnum getCol(){
return this.col;
}
此种情况下,存到数据库中的数据时col.ordinal()所q回的int数?br /> 2、数据库中enum_col的类型ؓ(oracle:varchar2,或者sql serverQvarchar)
@Column(name="enum_col")
public MyEnum getCol(){
return this.col;
}
此种情况下,存储到数据库中的gؓ定义此enum是所使用的名字如Q?br /> public enum MyEnum{
DATA1,
DATA2;
}
则,如果this.col代表DATA1则写DATA1到数据库中去?/pre>那么我们通过什么样的手D|改变q些呢?如果使用的是hibernate的话可以借助于UserType来实玎ͼ
首先、定义一个enum MyEnumDataQ?在持久化的时候把其code写到数据库中?
package ec.snow.hib.pojos;
public enum MyEnumData{
DATA1("data1",100),
DATA2("data2",200),
DATA3("data3",300);private String name;
private int code;
public int getCode(){
return this.code;
}
public String getName(){
return this.name;
}
MyEnumData(String name,int code){
this.name = name;
this.code = code;
}
//辅助ҎQ主要在UserType的实C通过相应的code得到MyEnumData
public static MyEnumData formCode(int code){
for(MyEnumData u:MyEnumData.values()){
if(u.getCode()==code)return u;
}
return null;
}
}//*******************************
接下来、定义相应的UserType的实玎ͼ
package com.snow.hib.pojos;import Java.io.Serializable;
import Java.sql.PreparedStatement;
import Java.sql.ResultSet;
import Java.sql.SQLException;
import Java.sql.Types;import org.hibernate.HibernateException;
import org.hibernate.usertype.UserType;/**
*@author anwxAn Weixiao
*@version $Id$
*/
public class MyEnumDataType implements UserType {
public int[] sqlTypes() {
int[] types = {Types.INTEGER};
return types;
}
public Class returnedClass(){
return UserTitle.class;
}
public boolean equals(Object x, Object y) throws HibernateException {
return x == y;
}
public int hashCode(Object x) throws HibernateException {
return x.hashCode();
}
public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
throws HibernateException, SQLException {
int code = rs.getInt(names[0]);
return rs.wasNull() ? null : MyEnumData.formCode(code);//notice code to use
}
public void nullSafeSet(PreparedStatement st, Object value, int index)
throws HibernateException, SQLException {
if (value == null) {
st.setNull(index, Types.INTEGER);
} else {
st.setInt(index, ((MyEnumData) value).getCode());
}
}
public Object deepCopy(Object value) throws HibernateException {
return value;
}
public boolean isMutable() {
return false;
}
public Serializable disassemble(Object value) throws HibernateException {
return (Serializable) deepCopy(value);
}
public Object assemble(Serializable cached, Object owner) throws HibernateException {
return deepCopy(cached);
}
public Object replace(Object original, Object target, Object owner)
throws HibernateException {
return deepCopy(original);
}
}//**********************************
最后、通过自定义的UserType来实现对enum的有效持久化
package com.snow.hib.pojos;import Java.io.Serializable;
import Javax.persistence.Column;
import Javax.persistence.Entity;
import Javax.persistence.Id;
import Javax.persistence.Table;import org.hibernate.annotations.Type;/**
*@author anwxAn Weixiao
*@version
*/
@Entity
@Table(name="my_def_type")
public class UseMyEnumData implements Serializable{
private static final long serialVersionUID = 6905822670746966787L;
private String id;
private String username;
private MyEnumData enumData;
@Column(updatable = true,nullable = true,name="MY_TITLE")
@Type(type="com.snow.hib.pojos.MyEnumDataType")
public MyEnumData getEnumData() {
return enumData;
}
public void setEnumData(MyEnumData data) {
this.enumData = data;
}
@Column(updatable=true,nullable = true,name="USER_NAME")
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}/**
* @return Returns the id.
*/
@Id
public String getId() {
return id;
}/**
* @param id The id to set.
*/
public void setId(String id) {
this.id = id;
}
}
下面是测试结果:
//***************************Test result
UseMyEnumData data = new UseMyEnumData();
data.setId("123456");
data.setTitle(MyEnumData.DATA1);
data.setUsername("chsi:manager");
manager.saveUseMyEnumData(title);
则数据库中写入的数据为: [123456 100 chsi:manager]
q有一炚w要注意的是,如果pȝ中用来媄?span class="hilite2">enumcd的数据可能有出现I值的时候hibernate在处理媄的时候会
?span class="hilite2">Enumcd影射为null,也就是没有对应的数据Q这在处理旧有系l数据的时候会有用处哦…………
]]>
Lucene集成——作为强大高效的索引擎,Lucene的美名早已久l考验了;
数据的自动插入和更新——当一个对象通过Hibernated或更新时Q烦引也会相应进行透明的更斎ͼ
支持众多复杂的搜索方式——可快速的使用通配W进行搜索,以及多关键词全文索(multi-word text searchesQ和q似或同义词搜烦Qapproximation/synonym searchesQ,或根据相x排列搜索结果;
搜烦集群QSearch ClusteringQ——Hibernate Search提供了内建搜索集解x案,其中包括一个基于JMS的异步查询和索引pȝQ?
对Lucene API接口的直接调用——如果用h处理某些特别复杂的问题Q可以在查询中直接用Lucene提供的API接口Q?
对Lucene的自动管理——Hibernate Search可以理q优化Lucene的烦引,q且非常高效C用Lucene的API接口?
目的主要目标包含以下几个方面:
易用性——和Hibernate的ORM映射一PHibernate Search帮助用户实现了业?0%的工作,q且使用户专注于余下更ؓ困难的业务实现部分;
和已有的Hibernate/JPA~程模型保持一致性——更L地集成Hibernate/JPA~程模型?#8220;一开始就致力要实现的目标”?/p>
scroll是用JDBC2.0的可滚动l果集实玎ͼquery.setMaxResults();query.setFirstResult()是数据库SQL语句实现?/p>
在数据库q行分页是首选的方式。数据库分页实际上是利用数据库本wSQL扩展的功能进行分,例如MySQL?limit 0,50q样的SQL语句。不但速度快,而且非常节省内存。不q不是每U数据库的都有这U分|持的SQLQ例如SQL Server׃支持?/p>
scroll是利用JDBC2.0的功能做分页的,那么完全取决于特定数据库的JDBC Driver的实C。事实上大部分JDBC Driver都是把所有的l果集都一ơ取到内存,然后再分늚。如果这个结果集非常大,例如几万条,不但E序执行速度会很慢,而且很容易导致out of memory。当然个别JDBC Driver使用了服务器端游标来实现Q那么就不会Dq种问题Q例如jTDS?/p>
q Object execute(HibernateCallback action)
q List execute(HibernateCallback action)
q两个方法都需要一?/span>HibernateCallback的实例,HibernateCallback实例可在M有效?/span>Hibernate数据讉K中用。程序开发者通过HibernateCallbackQ可以完全?/span>Hibernate灉|的方式来讉K数据库,解决Spring装Hibernate后灵zL不的~陷?/span>HibernateCallback是一个接口,该接口只有一个方?/span>doInHibernate(org.hibernate.Session session)Q该Ҏ只有一个参?/span>Session?/span>
通常Q程序中采用实现HibernateCallback的匿名内部类来获?/span>HibernateCallback的实例,ҎdoInHibernate的方法体是Spring执行的持久化操作。具体代码如下:
public class PersonDaoImpl implements PersonDao
{
// U有实例变量保存SessionFactory
private SessionFactory sessionFactory;
// 依赖注入必须的setterҎ
public void setSessionFactory(SessionFactory sessionFactory){
this.sessionFactory = sessionFactory;
}
/**
*
* 通过人名查找所有匹配该名的Person实例
*
* @param name
* 匚w的h?br />
*
* @return 匚w该Q命的全部Person集合
*
*/
public List findPersonsByName(final String name){
// 创徏HibernateTemplate实例
HibernateTemplate hibernateTemplate =new HibernateTemplate(this.sessionFactory);
// q回HibernateTemplate的execute的结?br />
return (List) hibernateTemplate.execute(
// 创徏匿名内部c?br />
new HibernateCallback(){
public Object doInHibernate(Session session) throws HibernateException{
// 使用条g查询的方法返?br />
List result = session.createCriteria(Person.class)
.add(Restrictions.like("name", name+"%").list();
return result;
}
});
}
}
q void delete(Object entity)Q删除指定持久化实例
q deleteAll(Collection entities)Q删除集合内全部持久化类实例
q find(String queryString)Q根?/span>HQL查询字符串来q回实例集合
q findByNamedQuery(String queryName)Q根据命名查询返回实例集?/span>
q get(Class entityClass, Serializable id)Q根据主键加载特定持久化cȝ实例
q save(Object entity)Q保存新的实?/span>
q saveOrUpdate(Object entity)Q根据实例状态,选择保存或者更?/span>
q update(Object entity)Q更新实例的状态,要求entity是持久状?/span>
q setMaxResults(int maxResults)Q设|分늚大小
属性名 | 用? |
---|---|
一个Hibernate cd允许Hibernate针对特定的关pL据库生成优化的SQL. 取?/span> | |
输出所有SQL语句到控制台. 有一个另外的选择是把q个log category设ؓ?eg. | | |
在log和console中打印出更漂亮的SQL?取?/span> | | |
在生成的SQL? 给定的schema/tablespace附加于非全限定名的表名上. 取?/span> | |
在生成的SQL? 给定的catalog附加于非全限定名的表名上. 取?/span> | |
创徏后,自动用这个名字绑定到JNDI? 取?/span> | |
为单向关?一对一, 多对一)的外q接抓取Qouter join fetchQ树讄最大深? gؓ意味着关闭默认的外连接抓? 取?/span> ?tt class=literal>?tt class=literal>之间取? | |
为Hibernate兌的批量抓取设|默认数? 取?/span> 的取gؓ, , ?tt class=literal> | |
为由q个打开的所有Session指定默认的实体表现模? 取?/span> , , | |
强制Hibernate按照被更新数据的主键QؓSQL更新排序。这么做减在高ƈ发系l中事务的死锁?取?/span> | | |
如果开? Hibernate收集有助于性能调节的统计数? 取?/span> | | |
如果开? 在对象被删除时生成的标识属性将被重设ؓ默认? 取?/span> | | |
如果开? Hibernate在SQL中生成有助于调试的注释信? 默认gؓ. 取?/span> | |
属性名 | 用? |
---|---|
非零|指定JDBC抓取数量的大?(调用). | |
非零|允许Hibernate使用JDBC2的批量更? 取?/span> ?tt class=literal>?tt class=literal>之间的? | |
如果你想让你的JDBC驱动?tt class=literal>q回正确的行计数 , 那么此属性设?tt class=literal>(开启这个选项通常是安全的). 同时QHibernateؓ自动版本化的数据使用扚wDML. 默认gؓ. eg. | | |
选择一个自定义?tt class=literal>. 多数应用E序不需要这个配|属? eg. | |
允许Hibernate使用JDBC2的可滚动l果? 只有在用用h供的JDBCq接Ӟq个选项才是必要? 否则Hibernate会用连接的元数? 取?/span> | | |
在JDBCd?tt class=literal> 的类型时使用?stream)(pȝU属?. 取?/span> | | |
在数据插入数据库之后Q允怋用JDBC3 来获取数据库生成的key(?。需要JDBC3+驱动和JRE1.4+, 如果你的数据库驱动在使用Hibernate的标 识生成器旉到问题,请将此D为false. 默认情况下将使用q接的元数据来判定驱动的能力. 取?/span> | |
自定?tt class=literal>的类? 此类用来向Hibernate提供JDBCq接. 取?/span> | |
讄JDBC事务隔离U别. 查看Java.sql.Connection来了解各个值的具体意义, 但请注意多数数据库都不支持所有的隔离U别. 取?/span> | |
允许被缓存的JDBCq接开启自动提?autocommit) (不徏?. 取?/span> | | |
指定Hibernate在何旉放JDBCq接. 默认情况?直到Session被显式关闭或被断开q接?才会释放JDBCq接. 对于应用E序服务器的JTA数据? 你应当?tt class=literal>, q样在每ơJDBC调用后,都会d的释放连? 对于非JTA的连? 使用在每个事务结束时释放q接是合理的. ؓJTA和CMT事务{略选择, 为JDBC事务{略选择. 取?/span> | | | | |
<propertyName> | JDBC属?tt class=literal>传递到中去. |
<propertyName> | 属?tt class=literal>传递到JNDI 中去. |
属性名 | 用? |
---|---|
自定义的的类? 取?/span> | |
以频J的L作ؓ代h, 优化二~存来最化写操? 在Hibernate3中,q个讄对的集群~存非常有用, 寚w缓存的实现而言Q默认是开启的. 取?/span> | |
允许查询~存, 个别查询仍然需要被讄为可~存? 取?/span> | |
能用来完全禁止用二U缓? 寚w些在cȝ映射定义中指?tt class=literal>的类Q会默认开启二U缓? 取?/span> | |
自定义实?tt class=literal>接口的类? 默认为内建的. 取?/span> | |
二~存区域名的前缀. 取?/span> | |
强制Hibernate以更人性化的格式将数据存入二~存. 取?/span> |
属性名 | 用? |
---|---|
一?tt class=literal>的类? 用于Hibernate API (默认?tt class=literal>). 取?/span> | |
一个JNDI名字Q被用来从应用服务器获取JTA . 取?/span> | |
一?tt class=literal>的类?- 当用JVMU缓存,或在JTA环境中用hilo生成器的时候需要该c? 取?/span> | |
如果开? session在事务完成后被自动清洗(flush)?现在更好的方法是使用自动session上下文管理?span class=strong>取?/span> | | |
如果开? session在事务完成后被自动关闭?现在更好的方法是使用自动session上下文管理?span class=strong>取?/span> | |
属性名 | 用? |
---|---|
?当前" 指定一?自定义的){略?span class=strong>eg. | | | |
选择HQL解析器的实现. 取?/span> or | |
Hibernate查询中的W号映射到SQL查询中的W号 (W号可能是函数名或常量名?. 取?/span> | |
?tt class=literal>创徏Ӟ自动查数据库l构Q或者将数据库schema的DDL导出到数据库. 使用 ?在显式关?tt class=literal>Ӟdrop掉数据库schema. 取?/span> | | | | |
开启CGLIB来替代运行时反射机制(pȝU属?. 反射机制有时在除错时比较有用. 注意即关闭q个优化, Hibernateq是需要CGLIB. 你不能在中设|此属? 取?/span> | |
你应当LZ的数据库?tt class=literal>属性设|成正确?子类. 如果你指定一U方a, Hibernateؓ上面列出的一些属性用合理的默认? Z省去了手工指定它们的功夫.
Hibernate SQL方言 ()RDBMS | 方言 |
---|---|
DB2 | |
DB2 AS/400 | |
DB2 OS390 | |
PostgreSQL | |
MySQL | |
MySQL with InnoDB | |
MySQL with MyISAM | |
Oracle (any version) | |
Oracle 9i/10g | |
Sybase | |
Sybase Anywhere | |
Microsoft SQL Server | |
SAP DB | |
Informix | |
HypersonicSQL | |
Ingres | |
Progress | |
Mckoi SQL | |
Interbase | |
Pointbase | |
FrontBase | |
Firebird |
cd | 功能 |
---|---|
在所有SQL DML语句被执行时为它们记录日? | |
为所有JDBC参数记录日志 | |
在所有SQL DDL语句执行时ؓ它们记录日志 | |
在session清洗(flush)Ӟ为所有与其关联的实体(最?0?的状态记录日? | |
为所有二U缓存的zd记录日志 | |
Z务相关的zd记录日志 | |
为所有JDBC资源的获取记录日? | |
在解析查询的时?记录HQL和SQL的AST分析日志 | |
为JAAS认证h做日? | |
ZQ何Hibernate相关信息做日?(信息量较? 但对查错非常有帮? |
Transaction工厂c? | 应用E序服务? |
---|---|
JBoss | |
Weblogic | |
WebSphere | |
WebSphere 6 | |
Orion | |
Resin | |
JOTM | |
JOnAS | |
JRun4 | |
Borland ES |
不过q里面也有些陷阱:如果你的试q是会把数据写入了数据库的话,可能是由于你加蝲的spring配置文g里有多个事务理器或session工厂,从而导致AbstractTransactionalDataSourceSpringContextTests没有获得正确的TransactionManager或SessionFactory,所以就没能回滚不过q种错误也不太容易犯,因ؓAbstractTransactionalDataSourceSpringContextTests默认按类型组?如果她发现有多个TransactionManagercd的bean是要报错?此时你需要调用setAutowireMode(this.AUTOWIRE_BY_NAME);使其按名U组装?br>
另外值得注意的是Q用MYSQL时候表的类型选择。例?/p>
CREATE TABLE `myisam` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(100) default NULL,
`content` text,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=gbk;
q时候应该把cd改ؓInnoDB?/span>
MySQL存储引擎包括处理事务安全表的引擎和处理非事务安全表的引擎Q?#183; MyISAM理非事务表。它提供高速存储和索,以及全文搜烦能力。MyISAM在所有MySQL配置里被支持Q它是默认的存储引擎Q除非你配置 MySQL默认使用另外一个引擎?·MEMORY存储引擎提供“内存?#8221;表。MERGE存储引擎允许集合被处理同样的MyISAM表作Z个单独的表。就像MyISAM一P MEMORY和MERGE存储引擎处理非事务表Q这两个引擎也都被默认包含在MySQL中?释:MEMORY存储引擎正式地被定为HEAP引擎?#183; InnoDB和BDB存储引擎提供事务安全表。BDB被包含在为支持它的操作系l发布的MySQL-Max二进制分发版里。InnoDB也默认被包括在所 有MySQL 5.1二进制分发版里,你可以按照喜好通过配置MySQL来允许或止M引擎?#183;EXAMPLE存储引擎是一?#8220;存根”引擎Q它不做什么。你可以用这?引擎创徏表,但没有数据被存储于其中或从其中检索?/span>
<!-- <filter>
<filter-name>Set Character Encoding</filter-name>
<filter-class>com.founder.study.forum.helper.FilterChar</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>-->
<filter>
<filter-name>webwork</filter-name>
<filter-class>com.opensymphony.webwork.dispatcher.FilterDispatcher</filter-class>
</filter>
<!-- <filter>
<filter-name>sitemesh</filter-name>
<filter-class>com.opensymphony.module.sitemesh.filter.PageFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>sitemesh</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>Set Character Encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>-->
<filter-mapping>
<filter-name>webwork</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.jsp</welcome-file>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<!--
This typically isn't required, as the taglib is included in webwork.jar.
If you really need a taglib configuration within web.xml, copy webwork/src/java/META-INF/taglib.tld
to the WEB-INF directory as webwork.tld.
-->
<taglib>
<taglib-uri>webwork</taglib-uri>
<taglib-location>/WEB-INF/lib/webwork-2.2.4.jar</taglib-location>
</taglib>
<!-- <taglib>
<taglib-uri>sitemesh-decorator</taglib-uri>
<taglib-location>/WEB-INF/sitemesh-decorator.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>sitemesh-page</taglib-uri>
<taglib-location>/WEB-INF/sitemesh-page.tld</taglib-location>
</taglib>-->
</web-app>
xwork.xml
<!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.1.1//EN" "http://www.opensymphony.com/xwork/xwork-1.1.1.dtd">
<xwork>
<include file="webwork-default.xml" />
<package name="default" extends="webwork-default">
<interceptors>
<interceptor-stack name="modelParamsStack">
<interceptor-ref name="model-driven" />
<interceptor-ref name="params" />
</interceptor-stack>
</interceptors>
</package>
</xwork>
webwork.properties
webwork.objectFactory = spring
webwork.devMode = true
webwork.tag.altSyntax=true
webwork.locale=zh_CN
webwork.i18n.encoding=UTF-8
webwork.custom.i18n.resources=com.founder.study.forum.resource.ApplicationResources
jdbc.properties
# Properties file with JDBC-related settings.
# Applied by PropertyPlaceholderConfigurer from "applicationContext-*.xml".
# Targeted at system administrators, to avoid touching the context XML files.
jdbc.driverClassName=org.gjt.mm.mysql.Driver
jdbc.url=jdbc:mysql://localhost:3306/forum?useUnicode=true&characterEncoding=utf-8
jdbc.username=root
jdbc.password=root
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.show_sql=true
hibernate.hbm2ddl.auto=update
applicationContext.xml
转自http://m.tkk7.com/black_zerg/archive/2005/05/30/5327.html
|
?/span> src 目录下ؓ Java 源码
dao
负责数据讉K对象的定义和实现
其中
Dao
l尾为接口,
Impl
l尾为实现。目前一般用
hibernate
做实现?br />
domain
实体对象 q里 service 是外观接口, serviceimpl 是实玎ͼ考虑目前情况单,q没有进一步分逻辑Q业务逻辑都在 impl 中完成?/span>
web
界面相关?/span>
Java
c?/span>
common 是一些常用类Q如处理中文问题?/span> filter. displaytag 中放?/span> displaytag 相关的类Q多?/span> wrapper. webwork 中都是对应的 action Q?/span> 其中 BaseAction 是基本的抽象c,基本后箋开发应l承此类 CrudAction 是ؓ了一般的 Crud 工作而作的一个抽象类Q可以承用来简化工作?/span> ?/span> CaseDispatcher 负责菜单点击后分发到相关 Action Q同时处理权限和 session 工作?br /> 其他 action 按模块进行了l织 |
|
左边?/span> webroot 的结?/span>
重要的配|文件有Q?/span>
Spring applicationContext.xml applicationContext-db.xml
Webwork xwork.xml webwork.properties
i18n labels.properties
log4j log4j.properties
displaytag displaytag.properties
dbConnect jdbc.properties |
关于一些技术难点和l节Q?/span>
1Q?span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">
各框架连接: spring ?/span> hibernate 使用 spring ?/span> hibernate 支持?/span> Spring ?/span> webwork 使用 autoware 的拦截机制自动装配?/span>2Q?span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">
列表的问题,采用 displaytag 。功能强大,使用z,可实现排序和数据导出?/span>3Q?span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">
数据下蝲Q?/span> displaytag 自带?/span> excel 下蝲4Q?span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">
文g上传Q?/span> webwork 提供的解x案,用拦截机制实现?/span>5Q?/span> jsp 代码l织斚wQ我们?/span> taglib ?/span> css 技术 jsp 中页面逻辑减少到最,一般情况完全可以不使用 <% %> ?/span> script D?/span> 。同时我们用两?/span> include 来包含常用的 taglib 定义Q?/span> js 引用?/span> html l构Q jsp 代码非常z?/span>
6Q?span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">
中文问题 我们使用 filter 来解决页?/span> gbk ?/span> Java E序 unicode 的{换,同时通过正确的设|数据库q接 url 完成和数据库之间的交互?/span>7Q?span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">
I18n 国际化。我们要求在 jsp 代码中不出现中文Q所有提CZ息都通过资源文g labels.properties 来完成。页面中可以使用 jstl ?/span> webwork 标签来调用?/span>8Q?span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">
界面验证问题。?/span> webwork ?/span> validate 机制?/span> xml 定义Q或?/span> action 中代码判断?/span>