2008年4月29日
#
其实就是关键一句话:
window.opener.document.getElementById("XXX").value=“123456”;
例程如下:
http://www.blogjava.net/Files/junglesong/ParentChildWnd20080520140659.rar
类之间关联的Hibernate表现
在Java程序中,类之间存在多种包含关系,典型的三种关联关系有:一个类拥有另一个类的成员,一个类拥有另一个类的集合的成员;两个类相互拥有对象的集合的成员.在Hibernate中,我们可以使用映射文件中的many-to-one, one-to-many, many-to-many来实现它们.这样的关系在Hibernate中简称为多对一,一对多和多对多.
多对一的类代码
事件与地点是典型的多对一关系,多个事件可以在一个地点发生(时间不同),一个地点可发生多个事件.它们的对应关系是(多)事件对(一)地点.
两个类的代码如右:
public class Event{
private String id;
private String name;
private Location location;
}
public class Location{
private String id;
private String name;
}
多对一的映射文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.hibernate.auction">
<class name="com.sitinspring.domain.Event"
table="Event_TB">
<id name="id" column="ID" >
<generator class="uuid.hex"/>
</id>
<property name="name" column="name" />
<many-to-one name="location" column="locationId" class="com.sitinspring.domain.Location"/>
</class>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.hibernate.auction">
<class name="com.sitinspring.domain.Location"
table="Location_TB">
<id name="id" column="ID" >
<generator class="uuid.hex"/>
</id>
<property name="name" column="name" />
</class>
</hibernate-mapping>
多对一的表数据
一对多的类代码
如果一个用户有多个权限,那么User类和Privilege类就构成了一对多的关系,User类将包含一个Privilege类的集合.
public class User{
private String id;
private String name;
private Set<Privilege> privileges=new LinkedHashSet<Privilege>();
}
public class Privilege{
private String id;
private String userId;
private int privilegeLevel;
}
一对多的映射文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.hibernate.auction">
<class name="com.sitinspring.domain.User"
table="User_TB">
<id name="id" column="ID" >
<generator class="uuid.hex"/>
</id>
<property name="name" column="name" />
<set name="privileges">
<key column="userId"/>
<one-to-many class="com.sitinspring.domain.Privilege"/>
</set>
</class>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.hibernate.auction">
<class name="com.sitinspring.domain.Privilege"
table="Privilege_TB">
<id name="id" column="ID" >
<generator class="uuid.hex"/>
</id>
<property name="userId" column="userId" />
<property name="privilegeLevel" column="privilegeLevel" />
</class>
</hibernate-mapping>
一对多的表数据
多对多
多对多关系 是指两个类相互拥有对方的集合,如文章和标签两个类,一篇文章可能有多个标签,一个标签可能对应多篇文章.要实现这种关系需要一个中间表的辅助.
类代码如右:
public class Article{
private String id;
private String name;
private Set<Tag> tags = new HashSet<Tag>();
}
public class Tag{
private String id;
private String name;
private Set<Article> articles = new HashSet<Article>();
}
多对多的映射文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.hibernate.auction">
<class name="com.sitinspring.domain.Article" table="ARTICLE_TB">
<id name="id" column="ID" >
<generator class="uuid.hex"/>
</id>
<property name="name" column="NAME" />
<set name="tags" table="ARTICLETAG_TB" cascade="all" lazy="false">
<key column="ARTICLEID" />
<many-to-many column="TAGID" class="com.sitinspring.domain.Tag" />
</set>
</class>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.hibernate.auction">
<class name="com.sitinspring.domain.Tag" table="TAG_TB">
<id name="id" column="ID" >
<generator class="uuid.hex"/>
</id>
<property name="name" column="NAME" />
<set name="articles" table="ARTICLETAG_TB" cascade="all" lazy="false">
<key column="TAGID" />
<many-to-many column="ARTICLEID" class="com.sitinspring.domain.Article" />
</set>
</class>
</hibernate-mapping>
多对多的表数据
源码下载:
http://www.blogjava.net/Files/junglesong/HibernateMapping20080430203526.rar
Criteria查询
Hibernate中的Criteria API提供了另一种查询持久化的方法。它让你能够使用简单的API动态的构建查询,它灵活的特性通常用于搜索条件的数量可变的情况。
Criteria查询之所以灵活是因为它可以借助Java语言,在Java的帮助下它拥有超越HQL的功能。Criteria查询也是Hibernate竭力推荐的一种面向对象的查询方式。
Criteria查询的缺点在于只能检索完整的对象,不支持统计函数,它本身的API也抬高了一定的学习坡度。
Criteria查询示例代码
Session session=HibernateUtil.getSession();
Criteria criteria=session.createCriteria(User.class);
// 条件一:名称以关开头
criteria.add(Restrictions.like("name", "关%"));
// 条件二:email出现在数组中
String[] arr={"1@2.3","2@2.3","3@2.3"};
criteria.add(Restrictions.in("email", arr));
// 条件三:password等于一
criteria.add(Restrictions.eq("password", "1"));
// 排序条件:按登录时间升序
criteria.addOrder(Order.asc("lastLoginTime"));
List<User> users=(List<User>)criteria.list();
System.out.println("返回的User实例数为"+users.size());
for(User user:users){
System.out.println(user);
}
HibernateUtil.closeSession(session);
Criteria查询实际产生的SQL语句
select
this_.ID as ID0_0_,
this_.name as name0_0_,
this_.pswd as pswd0_0_,
this_.email as email0_0_,
this_.lastLoginTime as lastLogi5_0_0_,
this_.lastLoginIp as lastLogi6_0_0_
from
USERTABLE_OKB this_
where
this_.name like '关%'
and this_.email in (
'1@2.3', '2@2.3', '3@2.3'
)
and this_.pswd='1'
order by
this_.lastLoginTime asc
注:参数是手工加上的。
HQL介绍
Hibernate中不使用SQL而是有自己的面向对象查询语言,该语言名为Hibernate查询语言(Hibernate Query Language).HQL被有意设计成类似SQL,这样开发人员可以利用已有的SQL知识,降低学习坡度.它支持常用的SQL特性,这些特性被封装成面向对象的查询语言,从某种意义上来说,由HQL是面向对象的,因此比SQL更容易编写.
本文将逐渐介绍HQL的特性.
查询数据库中所有实例
要得到数据库中所有实例,HQL写为”from 对象名”即可,不需要select子句,当然更不需要Where子句.代码如右.
Query query=session.createQuery("from User");
List<User> users=(List<User>)query.list();
for(User user:users){
System.out.println(user);
}
限制返回的实例数
设置查询的maxResults属性可限制返回的实例(记录)数,代码如右:
Query query=session.createQuery("from User order by name");
query.setMaxResults(5);
List<User> users=(List<User>)query.list();
System.out.println("返回的User实例数为"+users.size());
for(User user:users){
System.out.println(user);
}
分页查询
分页是Web开发的常见课题,每种数据库都有自己特定的分页方案,从简单到复杂都有.在Hibernate中分页问题可以通过设置firstResult和maxResult轻松的解决.
代码如右:
Query query=session.createQuery("from User order by name");
query.setFirstResult(3);
query.setMaxResults(5);
List<User> users=(List<User>)query.list();
System.out.println("返回的User实例数为"+users.size());
for(User user:users){
System.out.println(user);
}
条件查询
条件查询只要增加Where条件即可.
代码如右:
Hibernate中条件查询的实现方式有多种,这种方式的优点在于能显示完整的SQL语句(包括参数)如下.
select
user0_.ID as ID0_,
user0_.name as name0_,
user0_.pswd as pswd0_,
user0_.email as email0_,
user0_.lastLoginTime as lastLogi5_0_,
user0_.lastLoginIp as lastLogi6_0_
from
USERTABLE_OKB user0_
where
user0_.name like '何%'
public static void fetchByName(String prefix){
Session session=HibernateUtil.getSession();
Query query=session.createQuery("from User where name like'"+prefix+"%'");
List<User> users=(List<User>)query.list();
System.out.println("返回的User实例数为"+users.size());
for(User user:users){
System.out.println(user);
}
HibernateUtil.closeSession(session);
}
位置参数条件查询
HQL中也可以象jdbc中PreparedStatement一样为SQL设定参数,但不同的是下标从0开始.
代码如右:
public static void fetchByPos(String prefix){
Session session=HibernateUtil.getSession();
Query query=session.createQuery("from User where name=?");
// 注意下标是从0开始,和jdbc中PreparedStatement从1开始不同
query.setParameter(0, prefix);
List<User> users=(List<User>)query.list();
System.out.println("返回的User实例数为"+users.size());
for(User user:users){
System.out.println(user);
}
HibernateUtil.closeSession(session);
}
命名参数条件查询
使用位置参数条件查询最大的不便在于下标与?号位置的对应上,如果参数较多容易导致错误.这时采用命名参数条件查询更好.
使用命名参数时无需知道每个参数的索引位置,这样就可以节省填充查询参数的时间.
如果有一个命名参数出现多次,那在每个地方都会设置它.
public static void fetchByNamedParam(){
Session session=HibernateUtil.getSession();
Query query=session.createQuery("from User where name=:name");
query.setParameter("name", "李白");
List<User> users=(List<User>)query.list();
System.out.println("返回的User实例数为"+users.size());
for(User user:users){
System.out.println(user);
}
HibernateUtil.closeSession(session);
}
命名查询
命名查询是嵌在XML映射文件中的查询。通常,将给定对象的所有查询都放在同一文件中,这种方式可使维护相对容易些。命名查询语句写在映射定义文件的最后面。
执行代码如下:
Session session=HibernateUtil.getSession();
Query query=session.getNamedQuery("user.sql");
List<User> users=(List<User>)query.list();
System.out.println("返回的User实例数为"+users.size());
for(User user:users){
System.out.println(user);
}
HibernateUtil.closeSession(session);
映射文件节选:
<hibernate-mapping package="org.hibernate.auction">
<class name="com.sitinspring.domain.User"
table="USERTABLE_OKB" lazy="false">
<id name="id" column="ID" >
<generator class="uuid.hex"/>
</id>
<property name="name" column="name" />
<property name="password" column="pswd" />
<property name="email" column="email" />
<property name="lastLoginTime" column="lastLoginTime" />
<property name="lastLoginIp" column="lastLoginIp" />
</class>
<query name="user.sql">
<![CDATA[from User where email='2@2.3']]>
</query>
</hibernate-mapping>
主要的Hibernate组件
Configuration类
Configuration类启动Hibernate的运行环境部分,用于加载映射文件以及为它们创建一个SessionFacotry。完成这两项功能后,就可丢弃Configuration类。
// 从hibernate.cfg.xml创建SessionFactory 示例
sessionFactory = new Configuration().configure()
.buildSessionFactory();
SessionFactory类
Hibernate中Session表示到数据库的连接(不止于此),而SessionFactory接口提供Session类的实例。
SessionFactory实例是线程安全的,通常在整个应用程序中共享。
从Configuration创建SessionFacotry的代码如右。
// 从hibernate.cfg.xml创建SessionFactory 示例
SessionFactory sessionFactory = new Configuration().configure()
.buildSessionFactory();
Session类
Session表示到数据库的连接,session类的实例是到Hibernate框架的主要接口,使你能够持久化对象,查询持久化以及将持久化对象转换为临时对象。
Session实例不是线程安全的,只能将其用于应用中的事务和工作单元。
创建Session实例的代码如右:
SessionFactory sessionFactory = new Configuration().configure()
.buildSessionFactory();
Session session=sessionFactory.openSession();
保存一个对象
用Hibernate持久化一个临时对象也就是将它保存在Session实例中:
对user实例调用save时,将给该实例分配一个生成的ID值,并持久化该实例,在此之前实例的id是null,之后具体的id由生成器策略决定,如果生成器类型是assignd,Hibernate将不会给其设置ID值。
Flush()方法将内存中的持久化对象同步到数据库。存储对象时,Session不会立即将其写入数据库;相反,session将大量数据库写操作加入队列,以最大限度的提高性能。
User user=new User(“Andy”,22);
Session session=sessionFatory.openSession();
session.save(user);
session.flush();
session.close();
保存或更新一个对象
Hibernate提供了一种便利的方法用于在你不清楚实例对应的数据在数据库中的状态时保存或更新一个对象,也就是说,你不能确定具体是要保存save还是更新update,只能确定需要把对象同步到数据库中。这个方法就是saveOrUpdate。
Hibernate在持久化时会查看实例的id属性,如果其为null则判断此对象是临时的,在数据库中找不到对应的实例,其后选择保存这个对象;而不为空时则意味着对象已经持久化,应该在数据库中更新该对象,而不是将其插入。
User user=。。。;
Session session=sessionFatory.openSession();
session.saveOrUpdate(user);
Session.flush();
session.close();
删除一个对象
从数据库删除一个对象使用session的delete方法,执行删除操作后,对象实例依然存在,但数据库中对应的记录已经被删除。
User user=。。。;
Session session=sessionFatory.openSession();
session.delete(user);
session.flush();
session.close();
以ID从数据库中取得一个对象
如果已经知道一个对象的id,需要从数据库中取得它,可以使用Session的load方法来返回它。代码如右.
注意此放在id对应的记录不存在时会抛出一个HibernateException异常,它是一个非检查性异常。对此的正确处理是捕获这个异常并返回一个null。
使用此想法如果采用默认的懒惰加载会导致异常,对此最简单的解决方案是把默认的懒惰加载属性修改为false。如右:
User user=(User)session.load(User.class,"008");
session.close();
-----------------------------------------------
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.hibernate.auction">
<class name="com.sitinspring.domain.User"
table="USERTABLE_OKB" lazy="false">
<id name="id" column="ID" >
<generator class="uuid.hex"/>
</id>
。。。。
</class>
</hibernate-mapping>
检索一批对象
检索一批对象需要使用HQL,session接口允许你创建Query对象以检索持久化对象,HQL是面向对象的,你需要针对类和属性来书写你的HQL而不是表和字段名。
从数据库中查询所有用户对象如下:
Query query=session.createQuery(“from User”);// 注意这里User是类名,from前没有select。
List<User> users=(List<User>)query.list();
从数据库中查询名为“Andy”的用户如下:
String name=“Andy”;
Query query=session.createQuery(“from User where name=‘”+name+”’”);
List<User> users=(List<User>)query.list();
以上方法类似于Statement的写法,你还可以如下书写:
Query query=session.createQuery("from User user where user.name = :name");
query.setString("name", “Andy");
List<User> users=(List<User>)query.list();
Hibernate的映射文件
映射文件也称映射文档,用于向Hibernate提供关于将对象持久化到关系数据库中的信息.
持久化对象的映射定义可全部存储在同一个映射文件中,也可将每个对象的映射定义存储在独立的文件中.后一种方法较好,因为将大量持久化类的映射定义存储在一个文件中比较麻烦,建议采用每个类一个文件的方法来组织映射文档.使用多个映射文件还有一个优点:如果将所有映射定义都存储到一个文件中,将难以调试和隔离特定类的映射定义错误.
映射文件的命名规则是,使用持久化类的类名,并使用扩展名hbm.xml.
映射文件需要在hibernate.cfg.xml中注册,最好与领域对象类放在同一目录中,这样修改起来很方便.
领域对象和类
public class User{
// ID
private String id;
// 名称
private String name;
// 密码
private String password;
// 邮件
private String email;
// 上次登录时间
private String lastLoginTime;
// 上次登录ip
private String lastLoginIp;
public User(String name,String password,String email){
this.name=name;
this.password=password;
this.email=email;
}
}
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping package="org.hibernate.auction">
<class name="com.sitinspring.domain.User"
table="USERTABLE_OKB" lazy="false">
<id name="id" column="ID" >
<generator class="uuid.hex"/>
</id>
<property name="name" column="name" />
<property name="password" column="pswd" />
<property name="email" column="email" />
<property name="lastLoginTime" column="lastLoginTime" />
<property name="lastLoginIp" column="lastLoginIp" />
</class></hibernate-mapping>
hibernate.cfg.xml中的映射文件设置
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory name="java:comp/env/hibernate/SessionFactory">
<!-- JNDI数据源设置 -->
<property name="connection.datasource">
java:comp/env/jdbc/myoracle
</property>
<!-- SQL方言,org.hibernate.dialect.OracleDialect适合所有Oracle数据库 -->
<property name="dialect">
org.hibernate.dialect.OracleDialect
</property>
<!-- 显示SQL语句 -->
<property name="show_sql">true</property>
<!-- SQL语句整形 -->
<property name="format_sql">true</property>
<!-- 启动时创建表.这个选项在第一次启动程序时放开,以后切记关闭 -->
<!-- <property name="hbm2ddl.auto">create</property> -->
<!-- 持久化类的映射文件 -->
<mapping resource="com/sitinspring/domain/User.hbm.xml" />
<mapping resource="com/sitinspring/domain/Privilege.hbm.xml" />
<mapping resource="com/sitinspring/domain/Article.hbm.xml" />
<mapping resource="com/sitinspring/domain/Record.hbm.xml" />
</session-factory>
</hibernate-configuration>
映射文件物理位置示例
映射文件的基本结构
映射定义以hibernate-mapping元素开始, package属性设置映射中非限定类名的默认包.设置这个属性后,对于映射文件中列出的其它持久化类,只需给出类名即可.要引用指定包外的持久化类,必须在映射文件中提供全限定类名.
在hibernate-mapping标签之后是class标签.class标签开始指定持久化类的映射定义.table属性指定用于存储对象状态的关系表.class元素有很多属性,下面将逐个介绍.
ID
Id元素描述了持久化类的主码以及他们的值如何生成.每个持久化类必须有一个ID元素,它声明了关系表的主码.如右:
Name属性指定了持久化类中用于保存主码值的属性,该元素表明,User类中有一个名为id的属性.如果主码字段与对象属性不同,则可以使用column属性.
<id name="id" column="ID" >
<generator class="uuid.hex"/>
</id>
生成器
生成器创建持久化类的主码值.Hibernate提供了多个生成器实现,它们采用了不同的方法来创建主码值.有的是自增长式的,有点创建十六进制字符串, 还可以让外界生成并指定对象ID,另外还有一种Select生成器你那个从数据库触发器trigger检索值来获得主码值.
右边使用了用一个128-bit的UUID算法生成字符串类型的标识符, 这在一个网络中是唯一的(使用了IP地址)。UUID被编码为一个32位16进制数字的字符串 .这对字段类型是字符串的id字段特别有效.UUID作为ID字段主键是非常合适的,比自动生成的long类型id方式要好。
UUID示例
<id name="id" column="ID" >
<generator class="uuid.hex"/>
</id>
自动增长的id
<id name="id" column="ID" type="long">
<generator class="native"/>
</id>
属性
在映射定义中,property元素与持久化对象的一个属性对应,name表示对象的属性名,column表示对应表中的列(字段),type属性指定了属性的对象类型,如果type被忽略的话,Hibernate将使用运行阶段反射机制来判断类型.
<property name="name" column="name" />
<property name="password" column="pswd" />
<property name="email" column="email" />
<property name="lastLoginTime" column="lastLoginTime" />
<property name="lastLoginIp" column="lastLoginIp" />
获取Hibernate
在创建Hibernate项目之前,我们需要从网站获得最新的Hibernate版本。Hibernate主页是www.hibernate.org,找到其菜单中的download连接,选择最新的Hibernate版本即可。下载后将其解开到一个目录中。
右边是解开后的主要目录。其中最重要的是hibernate.jar,它包含全部框架代码;lib目录,包括Hibernate的所有依赖库;doc目录,包括JavDocs和参考文档。
Hibernate的配置文件
Hibernate能够与从应用服务器(受控环境,如Tomcat,Weblogic,JBoss)到独立的应用程序(非受控环境,如独立应用程序)的各种环境和谐工作,这在一定程度上要归功于其配置文件hibernate.cfg.xml,通过特定的设置Hibernate就能与各种环境配合。右边是hibernate.cfg.xml的一个示例。
配置Hibernate的所有属性是一项艰巨的任务,下面将依此介绍Hibernate部署将用到的基本配置。
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory name="java:comp/env/hibernate/SessionFactory">
<!-- JNDI数据源设置 -->
<property name="connection.datasource">
java:comp/env/jdbc/myoracle
</property>
<!-- SQL方言,org.hibernate.dialect.OracleDialect适合所有Oracle数据库 -->
<property name="dialect">
org.hibernate.dialect.OracleDialect
</property>
<!-- 显示SQL语句 -->
<property name="show_sql">true</property>
<!-- SQL语句整形 -->
<property name="format_sql">true</property>
<!-- 启动时创建表.这个选项在第一次启动程序时放开,以后切记关闭 -->
<!-- <property name="hbm2ddl.auto">create</property> -->
<!-- 持久化类的配置文件 -->
<mapping resource="com/sitinspring/domain/User.hbm.xml" />
<mapping resource="com/sitinspring/domain/Privilege.hbm.xml" />
<mapping resource="com/sitinspring/domain/Article.hbm.xml" />
<mapping resource="com/sitinspring/domain/Record.hbm.xml" />
</session-factory>
</hibernate-configuration>
使用Hibernate管理的JDBC连接
右边配置文件中的Database connection settings 部分制定了Hibernate管理的JDBC连接, 这在非受控环境如桌面应用程序中很常见。
其中各项属性为:
connection.driver_class:用于特定数据库的JDBC连接类
connection.url:数据库的完整JDBC URL
connection.username:用于连接到数据库的用户名
connection.password:用户密码
这种方案可用于非受控环境和基本测试,但不宜在生产环境中使用。
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
<property name="connection.url">jdbc:hsqldb:hsql://localhost</property>
<property name="connection.username">sa</property>
<property name="connection.password"></property>
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">1</property>
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.HSQLDialect</property>
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
。。。。。。。。
</session-factory>
</hibernate-configuration>
使用JNDI 数据源
在受控环境中,我们可以使用容器提供的数据源,这将使数据库访问更加快捷,右边就是使用Tomcat提供的数据源的配置部分。
附:Server.Xml中的数据源设置
<Context path="/MyTodoes" reloadable="true" docBase="E:\Program\Programs\MyTodoes" workDir="E:\Program\Programs\MyTodoes\work" >
<Resource name="jdbc/myoracle" auth="Container"
type="javax.sql.DataSource" driverClassName="oracle.jdbc.OracleDriver"
url="jdbc:oracle:thin:@192.168.104.173:1521:orcl"
username="hy" password="123456" maxActive="20" maxIdle="10"
maxWait="-1"/>
</Context>
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory name="java:comp/env/hibernate/SessionFactory">
<!-- JNDI数据源设置 -->
<property name="connection.datasource">
java:comp/env/jdbc/myoracle
</property>
<!-- SQL方言,org.hibernate.dialect.OracleDialect适合所有Oracle数据库 -->
<property name="dialect">
org.hibernate.dialect.OracleDialect
</property>
</hibernate-configuration>
数据库方言
Dialect属性能告知Hibernate执行特定的操作如分页时需要使用那种SQL方言,如MySql的分页方案和Oracle的大相径庭,如设置错误或没有设置一定会导致问题。
附录:常见的数据库方言
DB2 :org.hibernate.dialect.DB2Dialect
MySQL :org.hibernate.dialect.MySQLDialect
Oracle (any version) :org.hibernate.dialect.OracleDialect
Oracle 9i/10g :org.hibernate.dialect.Oracle9Dialect
Microsoft SQL Server :org.hibernate.dialect.SQLServerDialect
Sybase Anywhere :org.hibernate.dialect.SybaseAnywhereDialect
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory name="java:comp/env/hibernate/SessionFactory">
<!-- JNDI数据源设置 -->
<property name="connection.datasource">
java:comp/env/jdbc/myoracle
</property>
<!-- SQL方言,org.hibernate.dialect.OracleDialect适合所有Oracle数据库 -->
<property name="dialect">
org.hibernate.dialect.OracleDialect
</property>
<!-- 显示SQL语句 -->
<property name="show_sql">true</property>
<!-- SQL语句整形 -->
<property name="format_sql">true</property>
</hibernate-configuration>
其它属性
show_sql:它可以在程序运行过程中显示出真正执行的SQL语句来,建议将这个属性始终打开,它将有益于错误诊断。
format_sql:将这个属性设置为true能将输出的SQL语句整理成规范的形状,更方便用于查看SQL语句。
hbm2ddl.auto:将其设置为create能在程序启动是根据类映射文件的定义创建实体对象对应的表,而不需要手动去建表,这在程序初次安装时很方便。
如果表已经创建并有数据,切记关闭这个属性,否则在创建表时也会清除掉原有的数据,这也许会导致很严重的后果。
从后果可能带来的影响来考虑,在用户处安装完一次后就应该删除掉这个节点
<hibernate-configuration>
<session-factory name="java:comp/env/hibernate/SessionFactory">
。。。。。。
<!-- 显示SQL语句 -->
<property name="show_sql">true</property>
<!-- SQL语句整形 -->
<property name="format_sql">true</property>
<!-- 启动时创建表.这个选项在第一次启动程序时放开,以后切记关闭 -->
<!-- <property name="hbm2ddl.auto">create</property> -->
。。。。。。
</hibernate-configuration>
映射定义
在hibernate.cfg.xml中,还有一个重要部分就是映射定义,这些文件用于向Hibernate提供关于将对象持久化到关系数据库的信息。
一般来说,领域层有一个领域对象就有一个映射文件,建议将它们放在同一目录(domain)下以便查阅和修改,映射文件的命名规则是:持久化类的类名+.hbm.xml
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory name="java:comp/env/hibernate/SessionFactory">
<!-- JNDI数据源设置 -->
<property name="connection.datasource">
java:comp/env/jdbc/myoracle
</property>
。。。。。。
<!-- 持久化类的配置文件 -->
<mapping resource="com/sitinspring/domain/User.hbm.xml" />
<mapping resource="com/sitinspring/domain/Privilege.hbm.xml" />
<mapping resource="com/sitinspring/domain/Article.hbm.xml" />
<mapping resource="com/sitinspring/domain/Record.hbm.xml" />
</session-factory>
</hibernate-configuration>
本文假定读者已经熟知以下知识
能够熟练使用JDBC创建Java应用程序;
创建过以数据库为中心的应用
理解基本的关系理论和结构化查询语言SQL (Strutured Query Language)
Hibernate
Hibernate是一个用于开发Java应用的对象/关系映射框架。它通过在数据库中为开发人员存储应用对象,在数据库和应用之间提供了一座桥梁,开发人员不必编写大量的代码来存储和检索对象,省下来的精力更多的放在问题本身上。
持久化与关系数据库
持久化的常见定义:使数据的存活时间超过创建该数据的进程的存活时间。数据持久化后可以重新获得它;如果外界进程没有修改它,它将与持久化之前相同。对于一般应用来说,持久化指的是将数据存储在关系数据库中。
关系数据库是为管理数据而设计的,它在存储数据方面很流行,这主要归功于易于使用SQL来创建和访问。
关系数据库使用的模型被称为关系模型,它使用二维表来表示数据。这种数据逻辑视图表示了用户如何看待包含的数据。表可以通过主码和外码相互关联。主码唯一的标识了表中的一行,而外码是另一个表中的主码。
对象/关系阻抗不匹配
关系数据库是为管理数据设计的,它适合于管理数据。然而,在面向对象的应用中,将对象持久化为关系模型可能会遇到问题。这个问题的根源是因为关系数据库管理数据,而面向对象的应用是为业务问题建模而设计的。由于这两种目的不同,要使这两个模型协同工作可能具有挑战性。这个问题被称为 对象/关系阻抗不匹配(Object/relational impedance mismatch)或简称为阻抗不匹配
阻抗不匹配的几个典型方面
在应用中轻易实现的对象相同或相等,这样的关系在关系数据库中不存在。
在面向对象语言的一项核心特性是继承,继承很重要,因为它允许创建问题的精确模型,同时可以在层次结构中自上而下的共享属性和行为。而关系数据库不支持继承的概念。
对象之间可以轻易的实现一对一,一对多和多对多的关联关系,而数据库并不理解这些,它只知道外码指向主码。
对象/关系映射
前页列举了一些阻抗不匹配的问题,当然开发人员是可以解决这些问题,但这一过程并不容易。对象/关系映射(Object/Relational Mapping)就是为解决这些问题而开发的。
ORM在对象模型和关系模型之间架起了一座桥梁,让应用能够直接持久化对象,而不要求在对象和关系之间进行转换。Hibernate就是ORM工具中最成功的一种。它的主要优点是简单,灵活,功能完备和高效。
Hibernate的优点之一:简单
Hibernate不像有些持久化方案那样需要很多的类和配置属性,它只需要一个运行阶段配置文件已经为每个要持久化的应用对象指定一个XML格式的映射文件。
映射文件可以很短,让框架决定映射的其它内容,也可以通过制定额外的属性,如属性的可选列名,向框架提供更多信息。如右就是一个映射文档的示例。
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.hibernate.auction">
<class name="com.sitinspring.domain.User"
table="USERTABLE_OKB" lazy="false">
<id name="id" column="ID" >
<generator class="uuid.hex"/>
</id>
<property name="name" column="name" />
<property name="password" column="pswd" />
<property name="email" column="email" />
<property name="lastLoginTime" column="lastLoginTime" />
<property name="lastLoginIp" column="lastLoginIp" />
</class>
</hibernate-mapping>
Hibernate的优点之二:功能完备
Hibernate支持所有的面向对象特性,包括继承,自定义对象类型和集合。它可以让你创建模型时不必考虑持久层的局限性。
Hibernate提供了一个名为HQL的查询语言,它与SQL非常相似,只是用对象属性名代替了表的列。很多通过SQL实现的常用功能都能用HQL实现。
Hibernate的优点之三:高效
Hibernate使用懒惰加载提高了性能,在Hibernate并不在加载父对象时就加载对象集合,而只在应用需要访问时才生成。这就避免了检索不必要的对象而影响性能。
Hibernate允许检索主对象时选择性的禁止检索关联的对象,这也是一项改善性能的特性。
对象缓存在提高应用性能方面也发挥了很大的作用。Hibernate支持各种开源和缓存产品,可为持久化类或持久化对象集合启用缓存。
总结
在同一性,继承和关联三方面,对象模型和关系模型存在着阻抗不匹配,这是众多ORM框架致力解决的问题,hibernate是这些方案中最成功的一个,它的主要优点是简单,灵活,功能完备和高效。
使用Hibernate不要求领域对象实现特别的接口或使用应用服务器,它支持集合,继承,自定义数据类型,并携带一种强大的查询语言HQL,能减少很多持久化方面的工作量,使程序员能把更多精力转移到问题本身上来。
C/S 架构
C/S 架构是一种典型的两层架构,其全程是Client/Server,即客户端服务器端架构,其客户端包含一个或多个在用户的电脑上运行的程序,而服务器端有两种,一种是数据库服务器端,客户端通过数据库连接访问服务器端的数据;另一种是Socket服务器端,服务器端的程序通过Socket与客户端的程序通信。
C/S 架构也可以看做是胖客户端架构。因为客户端需要实现绝大多数的业务逻辑和界面展示。这种架构中,作为客户端的部分需要承受很大的压力,因为显示逻辑和事务处理都包含在其中,通过与数据库的交互(通常是SQL或存储过程的实现)来达到持久化数据,以此满足实际项目的需要。
C/S 架构的优缺点
优点:
1.C/S架构的界面和操作可以很丰富。
2.安全性能可以很容易保证,实现多层认证也不难。
3.由于只有一层交互,因此响应速度较快。
缺点:
1.适用面窄,通常用于局域网中。
2.用户群固定。由于程序需要安装才可使用,因此不适合面向一些不可知的用户。
3.维护成本高,发生一次升级,则所有客户端的程序都需要改变。
B/S架构
B/S架构的全称为Browser/Server,即浏览器/服务器结构。Browser指的是Web浏览器,极少数事务逻辑在前端实现,但主要事务逻辑在服务器端实现,Browser客户端,WebApp服务器端和DB端构成所谓的三层架构。B/S架构的系统无须特别安装,只有Web浏览器即可。
B/S架构中,显示逻辑交给了Web浏览器,事务处理逻辑在放在了WebApp上,这样就避免了庞大的胖客户端,减少了客户端的压力。因为客户端包含的逻辑很少,因此也被成为瘦客户端。
B/S架构的优缺点
优点:
1)客户端无需安装,有Web浏览器即可。
2)BS架构可以直接放在广域网上,通过一定的权限控制实现多客户访问的目的,交互性较强。
3)BS架构无需升级多个客户端,升级服务器即可。
缺点:
1)在跨浏览器上,BS架构不尽如人意。
2)表现要达到CS程序的程度需要花费不少精力。
3)在速度和安全性上需要花费巨大的设计成本,这是BS架构的最大问题。
4)客户端服务器端的交互是请求-响应模式,通常需要刷新页面,这并不是客户乐意看到的。(在Ajax风行后此问题得到了一定程度的缓解)
String的特殊之处
String是Java编程中很常见的一个类,这个类的实例是不可变的(immutable ).为了提高效率,JVM内部对其操作进行了一些特殊处理,本文就旨在于帮助大家辨析这些特殊的地方.
在进入正文之前,你需要澄清这些概念:
1) 堆与栈
2) 相同与相等,==与equals
3) =的真实意义.
栈与堆
1. 栈(stack)与堆(heap)都是Java用来在内存中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。每个函数都有自己的栈,而一个程序只有一个堆.
2. 栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。另外,栈数据可以共享,详见第3点。堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。 3. Java中的数据类型有两种。 一种是基本类型(primitive types), 共有8种,即int, short, long, byte, float, double, boolean, char(注意,并没有string的基本类型)。这种类型的定义是通过诸如int a = 3; long b = 255L;的形式来定义的,称为自动变量。值得注意的是,自动变量存的是字面值,不是类的实例,即不是类的引用,这里并没有类的存在。如int a = 3; 这里的a是一个指向int类型的引用,指向3这个字面值。这些字面值的数据,由于大小可知,生存期可知(这些字面值固定定义在某个程序块里面,程序块退出后,字段值就消失了),出于追求速度的原因,就存在于栈中。 另外,栈有一个很重要的特殊性,就是存在栈中的数据可以共享。假设我们同时定义 int a = 3; int b = 3; 编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找有没有字面值为3的地址,没找到,就开辟一个存放3这个字面值的地址,然后将a指向3的地址。接着处理int b = 3;在创建完b的引用变量后,由于在栈中已经有3这个字面值,便将b直接指向3的地址。这样,就出现了a与b同时均指向3的情况。 特别注意的是,这种字面值的引用与类对象的引用不同。假定两个类对象的引用同时指向一个对象,如果一个对象引用变量修改了这个对象的内部状态,那么另一个对象引用变量也即刻反映出这个变化。相反,通过字面值的引用来修改其值,不会导致另一个指向此字面值的引用的值也跟着改变的情况。如上例,我们定义完a与 b的值后,再令a=4;那么,b不会等于4,还是等于3。在编译器内部,遇到a=4;时,它就会重新搜索栈中是否有4的字面值,如果没有,重新开辟地址存放4的值;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b的值。 另一种是包装类数据,如Integer, String, Double等将相应的基本数据类型包装起来的类。这些类数据全部存在于堆中,Java用new()语句来显示地告诉编译器,在运行时才根据需要动态创建,因此比较灵活,但缺点是要占用更多的时间。
相同与相等,==与equals
在Java中,相同指的是两个变量指向的地址相同,地址相同的变量自然值相同;而相等是指两个变量值相等,地址可以不同.
相同的比较使用==,而相等的比较使用equals.
对于字符串变量的值比较来说,我们一定要使用equals而不是==.
=的真实意义
=即赋值操作,这里没有问题,关键是这个值有时是真正的值,有的是地址,具体来说会根据等号右边的部分而变化.
如果是基本类型(八种),则赋值传递的是确定的值,即把右边变量的值传递给左边的变量.
如果是类类型,则赋值传递的是变量的地址,即把等号左边的变量地址指向等号右边的变量地址.
指出下列代码的输出
String andy="andy";
String bill="andy";
if(andy==bill){
System.out.println("andy和bill地址相同");
}
else{
System.out.println("andy和bill地址不同");
}
String str=“andy”的机制分析
上页代码的输出是andy和bill地址相同.
当通过String str=“andy”;的方式定义一个字符串时,JVM先在栈中寻找是否有值为“andy”的字符串,如果有则将str指向栈中原有字符串的地址;如果没有则创建一个,再将str的地址指向它. String andy=“andy”这句代码走的是第二步,而String bill=“andy”走的是第一步,因此andy和bill指向了同一地址,故而andy==bill,andy和bill地址相等,所以输出是andy和bill地址相同.
这样做能节省空间—少创建一个字符串;也能节省时间—定向总比创建要省时.
指出下列代码的输出
String andy="andy";
String bill="andy";
bill="bill";
if(andy==bill){
System.out.println("andy和bill地址相同");
}
else{
System.out.println("andy和bill地址不同");
}
输出及解释
上页代码的输出是:andy和bill地址不同
当执行bill=“bill”一句时,外界看来好像是给bill变换了一个新值bill,但JVM的内部操作是把栈变量bill的地址重新指向了栈中一块值为bill的新地址,这是因为字符串的值是不可变的,要换值(赋值操作)只有将变量地址重新转向. 这样andy和bill的地址在执行bill=“bill”一句后就不一样了,因此输出是andy和bill地址不同.
指出下列代码的输出
String andy=new String("andy");
String bill=new String("andy");
// 地址比较
if(andy==bill){
System.out.println("andy和bill地址相同");
}
else{
System.out.println("andy和bill地址不同");
}
// 值比较
if(andy.equals(bill)){
System.out.println("andy和bill值相等");
}
else{
System.out.println("andy和bill值不等");
}
输出及机制分析
andy和bill地址不同
andy和bill值相等
我们知道new操作新建出来的变量一定处于堆中,字符串也是一样.
只要是用new()来新建对象的,都会在堆中创建,而且其字符串是单独存值的,即每个字符串都有自己的值,自然地址就不会相同.因此输出了andy和bill地址不同.
equals操作比较的是值而不是地址,地址不同的变量值可能相同,因此输出了andy和bill值相等.
指出下列代码的输出
String andy=new String("andy");
String bill=new String(andy);
// 地址比较
if(andy==bill){
System.out.println("andy和bill地址相同");
}
else{
System.out.println("andy和bill地址不同");
}
// 值比较
if(andy.equals(bill)){
System.out.println("andy和bill值相等");
}
else{
System.out.println("andy和bill值不等");
}
输出
andy和bill地址不同
andy和bill值相等
道理仍和第八页相同.只要是用new()来新建对象的,都会在堆中创建,而且其字符串是单独存值的,即每个字符串都有自己的值,自然地址就不会相同.
指出下列代码的输出
String andy="andy";
String bill=new String(“Bill");
bill=andy;
// 地址比较
if(andy==bill){
System.out.println("andy和bill地址相同");
}
else{
System.out.println("andy和bill地址不同");
}
// 值比较
if(andy.equals(bill)){
System.out.println("andy和bill值相等");
}
else{
System.out.println("andy和bill值不等");
}
输出及解析
andy和bill地址相同
andy和bill值相等
String bill=new String(“Bill”)一句在栈中创建变量bill,指向堆中创建的”Bill”,这时andy和bill地址和值都不相同;而执行bill=andy;一句后,栈中变量bill的地址就指向了andy,这时bill和andy的地址和值都相同了.而堆中的”Bill”则没有指向它的指针,此后这块内存将等待被垃圾收集.
指出下列代码的输出
String andy="andy";
String bill=new String("bill");
andy=bill;
// 地址比较
if(andy==bill){
System.out.println("andy和bill地址相同");
}
else{
System.out.println("andy和bill地址不同");
}
// 值比较
if(andy.equals(bill)){
System.out.println("andy和bill值相等");
}
else{
System.out.println("andy和bill值不等");
}
输出
andy和bill地址相同
andy和bill值相等
道理同第十二页
结论
使用诸如String str = “abc”;的语句在栈中创建字符串时时,str指向的字符串不一定会被创建!唯一可以肯定的是,引用str本身被创建了。至于这个引用到底是否指向了一个新的对象,必须根据上下文来考虑,如果栈中已有这个字符串则str指向它,否则创建一个再指向新创建出来的字符串. 清醒地认识到这一点对排除程序中难以发现的bug是很有帮助的。
使用String str = “abc”;的方式,可以在一定程度上提高程序的运行速度,因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。而对于String str = new String(“abc”);的代码,则一概在堆中创建新对象,而不管其字符串值是否相等,是否有必要创建新对象,从而加重了程序的负担。
如果使用new()来新建字符串的,都会在堆中创建字符串,而且其字符串是单独存值的,即每个字符串都有自己的值,且其地址绝不会相同
当比较包装类里面的数值是否相等时,用equals()方法;当测试两个包装类的引用是否指向同一个对象时,用==。
由于String类的immutable性质,当String变量需要经常变换其值如SQL语句拼接,HTML文本输出时,应该考虑使用StringBuffer类,以提高程序效率。