OOD面向对象
ORM实体映射
OOP持久化操作
用户通过框架提供的save()、update()、delete()进行增删改等操作
用户调用框架提供的hql或者criteria查询语言、本地SQL查询进行查询操作
配置hibernate环境
第一步:
链接数据库、创建数据源、把链接数据库的信息写在xml配置文件中(hibernate.cfg.xml),如用户名、密码、链
接字符串、驱动类
例(Mysql+Hibernate3.3):
<?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>
<!-- 数据库方言,让框架匹配其平台 -->
<!-- org.hibernate.dialet.Oracle10gDialect -->
<!-- 上方为oracle、下方为mysql、且各个版本有细微差别 -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 链接数据库的url -->
<property name="connection.url">jdbc:mysql://127.0.0.1:3306/lai</property>
<!-- 链接数据库的用户名 -->
<property name="connection.username">root</property>
<!-- 链接数据库的密码 -->
<property name="connection.password">root</property>
<!-- 数据库的JDBC驱动 -->
<!-- oracle.jdbc.driver.OracleDriver -->
<!-- 上方为oracle、下方为mysql -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- 在控制台运行时生成的sql语句,默认没有这一项 -->
<property name="show_sql">true</property>
<!-- 在控制台输出格式化的sql语句 -->
<property name="format_sql">true</property>
<!-- 在myeclipse上链接的工程 -->
<property name="myeclipse.connection.profile">lai</property>
<!-- 映射配置文件 -->
<mapping resource="entity/xw.hbm.xml"/>
</session-factory>
</hibernate-configuration>
第二步:
配置映射文件,一般映射文件命名<tablename>+.hbm.xml
例(xw.hbm.xml):
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<!-- name一般表示持久化类的全限定名(包名+类名) -->
<!-- table表示持久化对应的数据库表名 -->
<!-- catalog表示数据库名称 -->
<class name="id" table="xw" catalog="lai">
<!-- name表示持久化类属性名称 -->
<!-- type表示持久化类属性的类型 -->
<id name="XId" type="java.lang.Integer">
<!-- 表示持久化类对应的数据库表字段的名称 -->
<column name="x_id" />
<!-- generator是id元素的子元素,表示主键生成策略,本例是assigned -->
<generator class="assigned"></generator>
<!-- 常用的生成策略有
assigned 主键由应用程序生成或者用户提供,无需Hibernate干预
increment 对类型为long、short、int的类型数据按数值顺序递增,增值为1
identity 采用数据库提供的主键生成机制,如SQL Server、DB2、Mysql支持
标识符
sequence 采用数据库提供的sequence机制生成主键.如Oracle数据库(序号)
native 由Hibernate根据底层数据库自行判断采用何种主键生成策略
-->
</id>
<!-- name表示持久化类属性名称 -->
<!-- type表示持久化类属性的类型 -->
<property name="XTitle" type="java.lang.String">
<!-- 表示持久化类对应的数据库表字段的名称 -->
<column name="x_title" length="320" />
<!-- column元素常见的属性有
name 表示字段的名称
length 表示字段的长度
not-null 表示是否可以为空
default 表示默认的值
-->
</property>
<property name="XText" type="java.lang.String">
<column name="x_text" length="3200" />
</property>
<property name="XData" type="java.lang.String">
<column name="x_data" length="320" />
</property>
<property name="XFang" type="java.lang.String">
<column name="x_fang" length="320" />
</property>
</class>
</hibernate-mapping>
第三步:
使用Hibernate完成持久化操作
先构建工具类,让其管理session和SessionFactory HibernateSessionFactory.java
package tools;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
public class HibernateSessionFactory {
//创建安全线程,建立本地线程对象
private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
private static org.hibernate.SessionFactory sessionFactory;
private static Configuration configuration = new Configuration();
//指定配置文件
private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml";
static {
try {
configuration.configure(CONFIG_FILE_LOCATION);
sessionFactory = configuration.buildSessionFactory();
} catch (Exception e) {
System.err.println("%%%% 会话工厂创建失败 %%%%");
e.printStackTrace();
}
}
//私有方法,限制new方法实例化
private HibernateSessionFactory() {
}
//返回会话对象session
public static Session getSession() throws HibernateException {
Session session = (Session) threadLocal.get();
if (session == null || !session.isOpen()) {
//为空时重新创建
if (sessionFactory == null) {
try {
configuration.configure(CONFIG_FILE_LOCATION);
sessionFactory = configuration.buildSessionFactory();
} catch (Exception e) {
System.err.println("%%%% 会话工厂创建失败 %%%%");
e.printStackTrace();
}
}
session = (sessionFactory != null) ? sessionFactory.openSession()
: null;
threadLocal.set(session);
}
return session;
}
//关闭会话实例
public static void closeSession() throws HibernateException {
Session session = (Session) threadLocal.get();
threadLocal.set(null);
if (session != null) {
session.close();
}
}
//获取会话工厂的方法
public static org.hibernate.SessionFactory getSessionFactory() {
return sessionFactory;
}
//提供路径的方法,重新指定值
public static void setConfigFile(String configFile) {
HibernateSessionFactory.CONFIG_FILE_LOCATION = configFile;
sessionFactory = null;
}
//获取重新指定路径的configuration对象
public static Configuration getConfiguration() {
return configuration;
}
}
第四步:直接使用
Session session = HibernateSessionFactory.getSession();
Transaction tx = session.beginTransaction();
xw xws= new xw(null, "奇了", "hibernate", "可以添加", "访问量");
session.save(xws);
tx.commit();
HibernateSessionFactory.closeSession();
Hibernate:
select
max(x_id)
from
xw
Hibernate:
insert
into
lai.xw
(x_title, x_text, x_data, x_fang, x_id)
values
(?, ?, ?, ?, ?)
控制台可以看出,hibernate先查询出最大id,再通过最大id进行添加
(查)
根据主键加载对象:
Object get(Class class,Serializable id)方法:
如果为空,则返回null 即时加载
Object load(Class class,Serializable id)方法
如果为空,则抛出异常:org.hibernate.ObjectNotFoundException 延迟加载(可通过lazy改变,变成立即
加载)
(增)
xw xws = new xw(null, "奇了", "hibernate", "可以添加", "访问量");
session.save(xws);
(改)
xw xws = (xw) session.get(xw.class, new Integer(2));
xws.setXTitle("我是新的title");
(删)
xw xws = (xw) session.get(xw.class, new Integer(2));
session.delete(xws);
Hibernate中java对象的三种形态
瞬时状态(Transient) 持久状态(Persistent) 游离状态
(Detached)
xw xws = new xw(null, "奇了", "hibernate", "可以添加", "访问量");
当前属于瞬时状态,它和数据库中的数据没有任何关联
xw xws = (xw) session.get(xw.class, new Integer(2));
session.delete(xws);
当前属于持久状态,session会持续跟踪和管理这些对象,适当的时机,会提交数据,由hibernate固化到数据库中
xw xws= new xw(null, "奇了", "hibernate", "可以添加", "访问量");
session.save(xws);
tx.commit();
HibernateSessionFactory.closeSession();
当前属于游离状态,session关闭后,session实例失效,其从属的持久化对象xws变为游离状态
xw xws= new xw(null, "奇了", "hibernate", "可以添加", "访问量");
session.save(xws);
tx.commit();
session.delete(xws); //游离状态下的xws,可在提交数据后,进行删除游离对象
HibernateSessionFactory.closeSession();
刷新缓存机制:session.flush();
该方法在tx.commit();提交事务时默认调用.无需显示调用,主要用于刷新缓存,执行这些SQL语句,却不提交,所
以不会生效.储存过程.
数据更新的方法:
1、update()用于对游离的对象进行数据库更新操作,如没有OID,则报错
2、saveOrUpdate()如果传入的参数是瞬时状态,则调用save(),反之调用update().
瞬时时,如果存在,则报错org.hibernate.NonUniqueObjectException
3、merge()意为合并,如果该对象存在,则update(),反之save()
hibernate关系映射:
-------------------------------------BIN一对多关联映射BIN----------------------------------------
outer-join:分别是true,false,auto,默认是 auto。true: 表示使用外连接抓取关联的内容
fetch:来源查询fetch="select"
cascade:用于指定如何操纵与当前对象关联的其他对象
none:(默认值)忽略其他关联对象
save-update:当调用save()、update()、saveOrUpdate()方法来保存或更新当前对象时,级联保
存所有关联的瞬时状态和更新所有关联的游离状态
delete:当调用delete()方法删除当前对象时,同时级联删除所有关联对象
all:包含save-updata和delete的行为
all-delete-orphan:包含all及删除当前对象原有关联的"孤立"数据
inverse控制方向反转,如果为false,则为一方维护,反之由多方维护
一、单向多对一关联:
表关系如下:
部门表:id、部门name、city
create table dept(
d_id int auto_increment primary key,
d_name varchar(200),
d_loc varchar(200)
);
员工表:id、员工name、工作、外键
create table emp(
e_id int auto_increment,
e_name varchar(50),
e_job varchar(50),
emp_dept int,
primary key (e_id),
foreign key(emp_dept) references dept (d_id)
);
情景1、在emp类中定义了dept的实例属性,dept中无需定义用于存放emp对象的集合属性
emp.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.emp" table="emp" catalog="lai">
<id name="EId" type="java.lang.Integer">
<column name="e_id" />
<generator class="increment"></generator>
</id>
<many-to-one name="dept" class="entity.dept" fetch="select">
//name:持久化类的属性名;class:持久化类的类型;fetch:来源查询
<column name="emp_dept" />
</many-to-one>
<property name="EName" type="java.lang.String">
<column name="e_name" length="50" />
</property>
<property name="EJob" type="java.lang.String">
<column name="e_job" length="50" />
</property>
</class>
</hibernate-mapping>
dept.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.dept" table="dept" catalog="lai">
<id name="DId" type="java.lang.Integer">
<column name="d_id" />
<generator class="increment"></generator>
</id>
<property name="DName" type="java.lang.String">
<column name="d_name" length="200" />
</property>
<property name="DLoc" type="java.lang.String">
<column name="d_loc" length="200" />
</property>
</class>
</hibernate-mapping>
dept.java
private Integer DId;
private String DName;
private String DLoc;
emp.java
private Integer EId;
private dept dept;
private String EName;
private String EJob;
运行的java
dept Dept = new dept("bumen", "wuhan");
emp Emp1 = new emp(Dept, "zhangsan", "fangniu");
emp Emp2 = new emp(Dept, "lisi", "fangyang");
session.save(Dept);
session.save(Emp1);
session.save(Emp2);
运行结果:即使先save1、2,最后运行save(Dept),也能完成,多使用了updata语句,充分体现了面向对象语言的通
用性
Hibernate:select max(d_id) from dept
Hibernate:select max(e_id) from emp
Hibernate:insert into lai.dept (d_name, d_loc, d_id) values (?, ?, ?)
Hibernate:insert into lai.emp (emp_dept, e_name, e_job, e_id) values (?, ?, ?, ?)
Hibernate:insert into lai.emp (emp_dept, e_name, e_job, e_id) values (?, ?, ?, ?)
二、单向一对多关联:
情景2、dept中定义用于存放emp对象的集合属性,在emp类中无需定义dept的实例属性
Emp.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Emp" table="emp" catalog="lai">
<id name="EId" type="java.lang.Integer">
<column name="e_id" />
<generator class="increment"></generator>
</id>
<property name="EName" type="java.lang.String">
<column name="e_name" length="50" />
</property>
<property name="EJob" type="java.lang.String">
<column name="e_job" length="50" />
</property>
</class>
</hibernate-mapping>
Dept.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Dept" table="dept" catalog="lai">
<id name="DId" type="java.lang.Integer">
<column name="d_id" />
<generator class="increment"></generator>
</id>
<property name="DName" type="java.lang.String">
<column name="d_name" length="200" />
</property>
<property name="DLoc" type="java.lang.String">
<column name="d_loc" length="200" />
</property>
<!-- 持久化类的属性名 -->
<set name="emps">
<key>
<column name="emp_dept" />
<!-- 外键的字段名称 -->
</key>
<one-to-many class="entity.Emp" />
<!-- 多的持久化类 -->
</set>
</class>
</hibernate-mapping>
Dept.java
private Integer DId;
private String DName;
private String DLoc;
private Set<Emp> emps = new HashSet<Emp>(0);
Emp.java
private Integer EId;
private String EName;
private String EJob;
运行的java
Dept dept = new Dept("Abumen", "baijin");
Emp emp1 = new Emp("zs", "cs");
Emp emp2 = new Emp("ls", "fn");
dept.getEmps().add(emp1);
dept.getEmps().add(emp2);
session.save(dept);
session.save(emp1);
session.save(emp2);
运行结果:无论先运行那一方运行,都会多出update语句
Hibernate:select max(d_id) from dept
Hibernate:select max(e_id) from emp
Hibernate:insert into lai.dept (d_name, d_loc, d_id) values (?, ?, ?)
Hibernate:insert into lai.emp (e_name, e_job, e_id) values (?, ?, ?)
Hibernate:insert into lai.emp (e_name, e_job, e_id) values (?, ?, ?)
Hibernate:update lai.emp set emp_dept=? where e_id=?
Hibernate:update lai.emp set emp_dept=? where e_id=?
三、双向一对多关联:
情景3、dept中定义用于存放emp对象的集合属性,在emp类中定义dept的实例属性(结合上两者)
Emp.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Emp" table="emp" catalog="lai">
<id name="EId" type="java.lang.Integer">
<column name="e_id" />
<generator class="increment"></generator>
</id>
<many-to-one name="dept" class="entity.Dept" fetch="select">
<column name="emp_dept" />
</many-to-one>
<property name="EName" type="java.lang.String">
<column name="e_name" length="50" />
</property>
<property name="EJob" type="java.lang.String">
<column name="e_job" length="50" />
</property>
</class>
</hibernate-mapping>
Dept.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Dept" table="dept" catalog="lai">
<id name="DId" type="java.lang.Integer">
<column name="d_id" />
<generator class="increment"></generator>
</id>
<property name="DName" type="java.lang.String">
<column name="d_name" length="200" />
</property>
<property name="DLoc" type="java.lang.String">
<column name="d_loc" length="200" />
</property>
<!-- inverse控制方向反转,如果为false,则为一方维护,反之由多方维护 -->
<set name="emps" inverse="true" cascade="save-update">
<!-- cascade:用于指定如何操纵与当前对象关联的其他对象
none:(默认值)忽略其他关联对象
save-update:当调用save()、update()、saveOrUpdate()方法来保存或更新当前对象时,级联保
存所有关联的瞬时状态和更新所有关联的游离状态
delete:当调用delete()方法删除当前对象时,同时级联删除所有关联对象
all:包含save-updata和delete的行为
all-delete-orphan:包含all及删除当前对象原有关联的"孤立"数据
-->
<key>
<column name="emp_dept" />
</key>
<one-to-many class="entity.Emp" />
</set>
</class>
</hibernate-mapping>
Dept.java
private Integer DId;
private String DName;
private String DLoc;
private Set<Emp> emps = new HashSet<Emp>(0);
Emp.java
private Integer EId;
private Dept dept;
private String EName;
private String EJob;
运行的java
Dept dept = new Dept("部门1", "anhui");
Emp emp = new Emp(dept,"1", "2");
Emp emps = new Emp(dept,"1", "22222");
dept.getEmps().add(emp);
dept.getEmps().add(emps);
session.save(dept);
运行结果:添加Dept的同时,还能自动添加Emp对象
Hibernate:select max(d_id) from dept
Hibernate:select max(e_id) from emp
Hibernate:insert into lai.dept (d_name, d_loc, d_id) values (?, ?, ?)
Hibernate:insert into lai.emp (e_name, e_job, e_id) values (?, ?, ?)
Hibernate:insert into lai.emp (e_name, e_job, e_id) values (?, ?, ?)
情景4、删除Dept对象,同时删除关联的Emp对象
让inverse="true" cascade="delete"
运行的java
Dept dept = (Dept) session.load(Dept.class, new Integer(17));
session.delete(dept);
运行结果:删除Dept对象,和关联的Emp对象
Hibernate:select dept0_.d_id as d1_0_0_,dept0_.d_name as d2_0_0_,dept0_.d_loc as
d3_0_0_ from lai.dept dept0_ where dept0_.d_id=?
Hibernate:select emps0_.emp_dept as emp2_1_,emps0_.e_id as e1_1_,emps0_.e_id as e1_1_0_,
emps0_.emp_dept as emp2_1_0_,emps0_.e_name as e3_1_0_,emps0_.e_job as e4_1_0_ from
lai.emp emps0_ where emps0_.emp_dept=?
Hibernate:delete from lai.emp where e_id=?
Hibernate:delete from lai.emp where e_id=?
Hibernate:delete from lai.dept where d_id=?
情景5、清空Dept对象下所有关联的Emp对象
方式一、多方数据的外键列设为null,变成孤立数据
让inverse="false",且不设置cascade
运行的java
Dept dept = (Dept) session.load(Dept.class, new Integer(27));
dept.getEmps().clear();
运行结果:
Hibernate:select dept0_.d_id as d1_0_0_,dept0_.d_name as d2_0_0_,dept0_.d_loc as
d3_0_0_ from lai.dept dept0_ where dept0_.d_id=?
Hibernate:select emps0_.emp_dept as emp2_1_,emps0_.e_id as e1_1_,emps0_.e_id as e1_1_0_,
emps0_.emp_dept as emp2_1_0_,emps0_.e_name as e3_1_0_,emps0_.e_job as e4_1_0_ from
lai.emp emps0_ where emps0_.emp_dept=?
Hibernate:update lai.emp set emp_dept=null where emp_dept=?
方式二、永久删除
让inverse="true" cascade="all-delete-orphan"
运行的java
/**清空Dept对象下所有关联的Emp对象**/
Dept dept = (Dept) session.load(Dept.class, new Integer(27));
dept.getEmps().clear();
/**通过Emp对象,解除双向关联的关系(双向解除+删除)**/
Emp ems = (Emp) session.get(Emp.class, new Integer(2)); //查找对应的id的ems
Dept dept = (Dept) ems.getDept(); //查找对应的部门
ems.setDept(null); //让其变成孤立数据
dept.getEmps().remove(ems); //移除它
运行结果:Dept对象下关联的Emp对象全部被删除
Hibernate:select dept0_.d_id as d1_0_0_,dept0_.d_name as d2_0_0_,dept0_.d_loc as
d3_0_0_ from lai.dept dept0_ where dept0_.d_id=?
Hibernate:select emps0_.emp_dept as emp2_1_,emps0_.e_id as e1_1_,emps0_.e_id as e1_1_0_,
emps0_.emp_dept as emp2_1_0_,emps0_.e_name as e3_1_0_,emps0_.e_job as e4_1_0_ from
lai.emp emps0_ where emps0_.emp_dept=?
Hibernate:delete from lai.emp where e_id=?
-------------------------------------END一对多关联映射END----------------------------------------
-------------------------------------BIN多对多关联映射BIN----------------------------------------
四、多对多关联映射(由于引入了中间表,导致多对多关联性能不佳,避免在设计中大量使用)
表关系如下:
权限表:id、名称
create table privilege(
p_id int auto_increment,
p_name varchar(50),
primary key (p_id)
);
角色表:id、名字
create table role(
r_id int auto_increment,
rname varchar(50),
primary key (r_id)
);
关系映射表:
create table t_privilege_role(
pid int,
rid int,
foreign key(pid) references privilege (p_id),
foreign key(rid) references role (r_id)
);
Privilege.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Privilege" table="privilege" catalog="lai">
<id name="PId" type="java.lang.Integer">
<column name="p_id" />
<generator class="increment"></generator>
</id>
<property name="PName" type="java.lang.String">
<column name="p_name" length="50" />
</property>
<!-- 维护方反转,映射表, 在下方key和manytomany里的对应的数据,默认位于entity.Privilege-->
<set name="TPrivilegeRoles" table="t_privilege_role" inverse="true">
<key>
<!-- 在映射表中名称为pid,非空 -->
<column name="pid" not-null="true" />
</key>
<!-- 多对多关联,在entity.Role里(set name)TPrivilegeRoles -->
<many-to-many entity-name="entity.Role">
<!-- 在映射表中的名称为rid,非空 -->
<column name="rid" not-null="true"></column>
</many-to-many>
</set>
</class>
</hibernate-mapping>
Role.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Role" table="role" catalog="lai">
<id name="RId" type="java.lang.Integer">
<column name="r_id" />
<generator class="increment"></generator>
</id>
<property name="rname" type="java.lang.String">
<column name="rname" length="50" />
</property>
<set name="TPrivilegeRoles" table="t_privilege_role" cascade="save-update">
<key>
<column name="rid" not-null="true" />
</key>
<many-to-many entity-name="entity.Privilege">
<column name="pid" not-null="true"></column>
</many-to-many>
</set>
</class>
</hibernate-mapping>
Privilege.java
private Integer PId;
private String PName;
private Set TPrivilegeRoles = new HashSet(0);
Role.java
private Integer RId;
private String rname;
private Set TPrivilegeRoles = new HashSet(0);
运行的java
Role role1 = new Role("会计");
Role role2 = new Role("人事");
Privilege privilege1 = new Privilege("员工信息表");
Privilege privilege2 = new Privilege("查询工资表");
role1.getTPrivilegeRoles().add(privilege2);
role2.getTPrivilegeRoles().add(privilege1);
session.save(role1);
session.save(role2);
结果:
mysql> select * from t_privilege_role;
+------+------+
| pid | rid |
+------+------+
| 1 | 1 |
| 2 | 2 |
+------+------+
2 rows in set (0.00 sec)
mysql> select * from privilege;
+------+-----------------+
| p_id | p_name |
+------+-----------------+
| 1 | 鏌ヨ宸ヨ祫琛? |
| 2 | 鍛樺伐淇℃伅琛? |
+------+-----------------+
2 rows in set (0.00 sec)
mysql> select * from role;
+------+--------+
| r_id | rname |
+------+--------+
| 1 | 浼氳 |
| 2 | 浜轰簨 |
+------+--------+
-------------------------------------END多对多关联映射END----------------------------------------
五、一对一关联映射
表关系如下:
-------------------------------------BIN外键映射BIN----------------------------------------
方法1、外键映射
公民表:id、名字、年龄、男女、归属地
create table Citizenl(
c_id int auto_increment,
c_name varchar(30),
c_age int,
c_gender varchar(2),
c_address varchar(200),
primary key (c_id)
);
身份证表:id、外键、身份证号
create table IDCardl(
I_id int auto_increment,
c_id int,
I_idno varchar(18) unique,
primary key (I_id),
foreign key(c_id) references Citizenl (c_id)
);
Citizenl.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Citizenl" table="citizenl" catalog="lai">
<id name="CId" type="java.lang.Integer">
<column name="c_id" />
<generator class="increment"></generator>
</id>
<property name="CName" type="java.lang.String">
<column name="c_name" length="30" />
</property>
<property name="CAge" type="java.lang.Integer">
<column name="c_age" />
</property>
<property name="CGender" type="java.lang.String">
<column name="c_gender" length="2" />
</property>
<property name="CAddress" type="java.lang.String">
<column name="c_address" length="200" />
</property>
<!-- 将entity.Citizenl内idcardls与entity.Idcardl里citizenl关联 -->
<one-to-one name="idcardls" class="entity.Idcardl" property-ref="citizenl"></one-to-one>
</class>
</hibernate-mapping>
IDCardl.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Idcardl" table="idcardl" catalog="lai">
<id name="IId" type="java.lang.Integer">
<column name="I_id" />
<generator class="increment" />
</id>
<!-- 多对一,entity.Idcardl中citizenl,与entity.Citizenl关联 -->
<many-to-one name="citizenl" class="entity.Citizenl" fetch="select" cascade="all" >
<column name="c_id" unique="true" />
</many-to-one>
<property name="IIdno" type="java.lang.String" not-null="true">
<column name="I_idno" length="18" />
</property>
</class>
</hibernate-mapping>
Citizenl.java
private Integer CId;
private String CName;
private Integer CAge;
private String CGender;
private String CAddress;
private Set<Idcardl> idcardls = new HashSet<Idcardl> (0);
IDCardl.java
private Integer IId;
private Citizenl citizenl;
private String IIdno;
运行的java
Citizenl cit = new Citizenl("张三", 12, "男", "东莞");
Idcardl idc = new Idcardl("421102938271918231");
cit.getIdcardls().add(idc);
idc.setCitizenl(cit);
session.save(idc);
运行结果:
mysql> select * from idcardl;
+------+------+--------------------+
| I_id | c_id | I_idno |
+------+------+--------------------+
| 1 | 1 | 421102938271918231 |
+------+------+--------------------+
1 row in set (0.00 sec)
mysql> select * from Citizenl;
+------+--------+-------+----------+-----------+
| c_id | c_name | c_age | c_gender | c_address |
+------+--------+-------+----------+-----------+
| 1 | 寮犱笁 | 12 | 鐢? | 涓滆帪 |
+------+--------+-------+----------+-----------+
1 row in set (0.00 sec)
-------------------------------------END外键映射END----------------------------------------
-------------------------------------BIN主键映射BIN----------------------------------------
方法2、主键映射
公民表:id(主键加外键)、名字、年龄、男女、归属地
create table Citizen2(
c_id int auto_increment,
c_name varchar(30),
c_age int,
c_gender varchar(2),
c_address varchar(200),
primary key (c_id),
foreign key(c_id) references IDCard2 (I_id)
);
身份证表:id、身份证号
create table IDCard2(
I_id int auto_increment,
I_idno varchar(18) unique,
primary key (I_id)
);
Citizen2.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Citizen2" table="citizen2" catalog="lai">
<id name="CId" type="java.lang.Integer">
<column name="c_id" />
<!-- 根据xxx的外键生成主键 -->
<generator class="foreign">
<param name="property">idcard2</param>
</generator>
</id>
<!-- 当前主键存在一个约束 constrained="true" -->
<!-- 将两个类关联起来 -->
<one-to-one name="idcard2" class="entity.Idcard2" constrained="true" >
</one-to-one>
<property name="CName" type="java.lang.String">
<column name="c_name" length="30" />
</property>
<property name="CAge" type="java.lang.Integer">
<column name="c_age" />
</property>
<property name="CGender" type="java.lang.String">
<column name="c_gender" length="2" />
</property>
<property name="CAddress" type="java.lang.String">
<column name="c_address" length="200" />
</property>
</class>
</hibernate-mapping>
IDCard2.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Idcard2" table="idcard2" catalog="lai">
<id name="IId" type="java.lang.Integer">
<column name="I_id" />
<generator class="increment"></generator>
</id>
<property name="IIdno" type="java.lang.String">
<column name="I_idno" length="18" unique="true" />
</property>
<!-- 关联类 -->
<one-to-one name="citizen2" class="entity.Citizen2" cascade="all"></one-to-one>
</class>
</hibernate-mapping>
Citizen2.java
private Integer CId;
private Idcard2 idcard2;
private String CName;
private Integer CAge;
private String CGender;
private String CAddress;
Idcard2.java
private Integer IId;
private String IIdno;
private Citizen2 citizen2;
运行的java代码
Idcard2 id = new Idcard2("1111111321111");
Citizen2 ci = new Citizen2("mie", 18, "男", "日本");
id.setCitizen2(ci);
ci.setIdcard2(id);
session.save(id);
运行结果:
mysql> select * from IDCard2;
+------+----------------+
| I_id | I_idno |
+------+----------------+
| 2 | 1111111321111 |
| 1 | 11211111321111 |
+------+----------------+
2 rows in set (0.00 sec)
mysql> select * from Citizen2;
+------+--------+-------+----------+-----------+
| c_id | c_name | c_age | c_gender | c_address |
+------+--------+-------+----------+-----------+
| 1 | mie | 18 | 鐢? | 鏃ユ湰 |
| 2 | mie | 18 | 鐢? | 鏃ユ湰 |
+------+--------+-------+----------+-----------+
2 rows in set (0.00 sec)
-------------------------------------END主键映射END----------------------------------------
Hibernate数据加载
加载策略:lazy
类级别:<class ... lazy="true">(默认)true延迟加载||false立即加载
一对多关联级别:<set ... lazy="true">(默认)true延迟加载||false立即加载||extra增强延迟加载
多对一关联级别:<many-to-one ... lazy="proxy">(默认)proxy延迟加载||no-proxy无代理延迟加载||false立
即加载
多对多关联级别:<many-to-many ... lazy="proxy" />(默认)proxy延迟加载||false立即加载
利用load方法加载对象,不会访问表中的select语句,会生成一个对应表的代理类,代理类拥有一个属性,主键。
Dept dept = (Dept)session.load(Dept.class,new Interger(10)); //此时的dept就属于一个代理实例
在session关闭后,对应的代理实例就无法初始化
如果一对多中set标签中采用的是立即加载,那么,对一操作时,同时也会加载多,造成了性能的耗费
只有当dept初始化时,才会访问数据库加载,调用其Set集合:
Set<Emp> emps = dept.getEmps();
Interator it = emps.interator()、size()、isEmpty()、contains();
Hibernate.initialize(emps); //初始化
当使用增强延迟加载的时候:他不会查询所有的emp对象,他会比较聪明的发送聚合函数查询数据的记录数,起到
性能优化的作用
Dept dept = (Dept)session.load(Dept.class,new Interger(10));
Set<Emp> emps = dept.getEmps();
int Count = emps.size();
无代理延迟加载,是指只有遇到代理实例,才开始访问数据库,加载程序
立即加载,逐行加载,贼耗性能
OpenSessionInView模式
在视图层打开session:用户每次请求过程中都保持一个Session对象打开
配置流程:
配置文件中加入
<!-- session绑定到当前线程OpenSessionIn View -->
<property name="hibernate.current_session_context_class">thread</property>
创建过滤器类
public class OpenSessionInViewFilter implements Filter{
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// TODO Auto-generated method stub
Transaction tx = null;
try {
Session session = HibernateSessionFactory.getSessionFactory
().getCurrentSession();
tx=session.beginTransaction();
chain.doFilter(request, response);
//返回响应时提交事务
tx.commit();
} catch (HibernateException e) {
// TODO: handle exception
e.printStackTrace();
tx.rollback();
}finally{
HibernateSessionFactory.closeSession();
}
}
@Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
}
web.xml配置上面的filter
<filter>
<filter-name>openSessionInView</filter-name>
<filter-class>tools.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>openSessionInView</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
实际调用的时候:
//通过id返回该对象的代理类
public class DeptDaoImpl {
public Citizen2 getCitizen2(Integer id){
//这里获取的Session对象就是OpenSessionInViewFilter过滤器中打开的session,无需关闭session,
回到过滤器中会自己关闭
Session session = HibernateSessionFactory.getSessionFactory().getCurrentSession
();
//通过getCurrentSession创建的session会在事务提交后,或事物回滚,自动关闭
return (Citizen2) session .get(Citizen2.class, id);
}
}
Hibernate查询
一、HQL:Hibernate Query Language 语法与SQL类似,但它是面向对象的,SQL是关系型数据
[select/delete/update...][from 实体类][where...][group by ...][having...][order by ...]
例:
String hql = "from Citizen2"; //编写hql语句
Query query = session.createQuery(hql); //创建Query对象
List<Citizen2> idcard2 = query.list(); //得到封装好的结果
System.out.println(idcard2.size()); //打印个数
for (Citizen2 citizen2 : idcard2) {
System.out.println(citizen2.getCAge()); //打印输出对应的属性
}
解析:from Citizen2.其中select部分可以省略,from等关键词可以大小写随意写,但是Citizen2只能这么些,这
表示一个类名.
不允许有大小写的出入,完整的写法,select e from Citizen2 as e,as可以省略,不能写成select * from
Citizen2 e.其中e
表示对象名称,表示查询整个对象
/**执行时遇到了错误antlr.collections.AST.getLine()异常,原因是struts中的antlr2.x过时,和hibernate里
的antlr2.7.6冲突**/
/**解决方法:删除Myeclipse文件夹下/configuration/org.eclipse.osgi下删除,再在/plugins/下搜索
*struts*,用压缩包打开删除掉,防止自动生成**/
带条件查询:
String hql = "from Citizen2 where CAge=?"; //条件语句,这里查询的是对象里的参
数,不是数据库里的
//from Citizen2 e where e.CAge=?也行
Query query = session.createQuery(hql); //创建Query对象
query.setInteger(0, 18); //填充条件,第一个问号,jdbc从1开始
,hql从0开始
//setParameter可填充任意形式的字符,int,String
List<Citizen2> idcard2 = query.list();
for (Citizen2 citizen2 : idcard2) {
System.out.println(citizen2.getCAddress());
}
模糊查询(链式写法):
String hql = "from Citizen2 where CName like ? and CAge>? ";
Query query = session.createQuery(hql);
List<Citizen2> cit = query.getString(0,"%运%"),setInteger(1,20).list();
也可以用名字占位(先后顺序可以打乱,参数前面加":"):
String hql = "from Citizen2 where CName like :name and CAge> :age ";
Query query = session.createQuery(hql);
List<Citizen2> cit = query.getString("name","%运%"),setInteger("age",20).list();
主键查询(你确定只有一个结果值时):
String hql = "from Citizen2 where CName like ? and CAge>? ";
Query query = session.createQuery(hql);
Citizen2 cit = query.getString(0,"%运%"),setInteger(1,20).uniqueResult();
投影查询(说的辣么高级,其实就是一般的查询列,最后用Object[]封装而已,类似数组调用):
String hql = "select CId,CName from Citizen2";
Query query = session.createQuery(hql);
List<Object[]> idcard2 = query.list();
for (Object[] obj : idcard2) {
System.out.println(obj[0]+""+obj[1]);
}
返回的是部分值,和上面不同的是List<e>类型,弊端在于需要创建对应的构造函数(new ...)
String hql = "select new Citizen2(CId,CName) from Citizen2";
Query query = session.createQuery(hql);
List<Citizen2> idcard2 = query.list();
for (Citizen2 citizen2 : idcard2) {
System.out.println(citizen2.getCName()+" "+citizen2.getCId());
}
排序(默认情况下,按照升序顺序排序):下面是降序排序(order by e.CId desc)
String hql = "select e from Citizen2 e order by e.CId desc";
Query query = session.createQuery(hql);
List<Citizen2> idcard2 = query.list();
for (Citizen2 citizen2 : idcard2) {
System.out.println(citizen2.getCName()+" "+citizen2.getCId());
}
分页(setFirstResult(n),setMaxResults(m))
String hql ="from Citizen2";
Query query = session.createQuery(hql);
//setFirstResult(0)设置第一条记录的开始位置,这里从0开始.setMaxResults(5):设置每页
显示的大小
query.setFirstResult(0).setMaxResults(5);//查询结果1,2,3,4,5
List<Citizen2> cit = query.list();
for (Citizen2 citizen2 : cit) {
System.out.println(citizen2.getCId());
}
聚合函数(MYSQL中与HQL中对比)
mysql> select count(*) from Citizen2; String hql ="select count(e) from Citizen2 e";
+----------+ //这里第一个e可以换成*或者其他参数,如CId···
| count(*) | Query query = session.createQuery(hql);
+----------+
| 10 | Long count = (Long)query.uniqueResult();
+----------+
1 row in set (0.00 sec) System.out.println(count);结果都是10
mysql> select min(c_id) from Citizen2; String hql ="select max(CId),min(CId),avg(CId)
from Citizen2 e";
+-----------+
| min(c_id) | Query query = session.createQuery(hql);
+-----------+
| 1 | Object[] count = (Object[])query.uniqueResult();
+-----------+
1 row in set (0.00 sec) for (int i = 0; i < count.length; i++) {
System.out.println(count[i]+"\t");
}
内链接:inner join||join
迫切内链接:inner join fetch||join fetch
左链接(迫切):left outer join (fetch)||left join (fetch)
右链接(迫切):right outer join (fetch) || right join
当然HQL还支持分组查询、子查询、表连接(拼接)等,不细细讲了
Double d = 2.1111;//在制作商场网站时,需要制作Double调换,将Double转换精度
new DecimalFormat("0.000").format(d);
二、QBC:Query By Criteria 是一组API提供了完全面向对象的接口、类、方法
专用于对SQL不太熟悉的开发者,主要使用到了Criteria对象,使用add()方法加入查询条件,使用list()方法执行
查询语句.设置条件,
用的比较多的是Restrictions类,而不是Expression类
例子:查询该表
Criteria crit = session.createCriteria(Citizen2.class);
List<Citizen2> list = crit.list();
for (Citizen2 citizen2 : list) {
System.out.println(citizen2.getCName());
}
例子:排序(传入的一样是类中字段,不是表中字段)
Criteria crit = session.createCriteria(Citizen2.class);
crit.addOrder(Order.desc("CId"));
List<Citizen2> list = crit.list();
for (Citizen2 citizen2 : list) {
System.out.println(citizen2.getCName());
}
例子:分页查询(和HQL的分页类似,使用了setFirstResult()、setMaxResults()方法)
Criteria crit = session.createCriteria(Citizen2.class);
crit.setFirstResult(0).setMaxResults(3);
List<Citizen2> list = crit.list();
for (Citizen2 citizen2 : list) {
System.out.println(citizen2.getCName());
}
例子:条件查询(年龄等于22的)
Criteria crit = session.createCriteria(Citizen2.class);
crit.add(Restrictions.eq("CAge", 22));
List<Citizen2> list = crit.list();
for (Citizen2 citizen2 : list) {
System.out.println(citizen2.getCName());
}
Restrictions查询常用方法:
Restrictions.eq() 对应SQL的等于
Restrictions.allEq() 使用Map,对应多个相等的值对比
Restrictions.gt() 对应的SQL大于
Restrictions.ge() 对应的SQL大于等于
Restrictions.lt() 对应的SQL小于
Restrictions.le() 对应的小于等于
Restrictions.between() 对应的between子句
Restrictions.like() 对应的SQL的like子句
Restrictions.in() 对应的SQL的in子句
Restrictions.and() 对应的SQL的and子句
Restrictions.or() 对应的SQL的or子句
Restrictions.not() 对应的SQL的not子句
Restrictions.disjunction() 针对三个及三个以上的or或and条件查询(如下:)
Criteria crit = session.createCriteria(Citizen2.class).add(Restrictions.disjunction().add
(Restrictions.gt("",""))
.add(Restrictions.ge("","")).add(Restrictions.eq("","")));
Restrictions.conjunction() 针对三个或者三个以上的and操作,将上述改成这个方法即可
Example查询(主要用于查询条件较多的时候,会把查询条件封装成一个类):
例子:
Citizen2 cit = new Citizen2();
cit.setCAge(22);
cit.setCName("乐运来");
cit.setCAddress("武汉市");
Criteria crit = session.createCriteria(Citizen2.class);
List<Citizen2> list = crit.add(Example.create(cit)).list();
for (Citizen2 citizen2 : list) {
System.out.println(citizen2.getCId()+citizen2.getCAddress());
}
//List<Citizen2> list = crit.add(Example.create(cit).excludeProperty
("CName")).list();
还可以后面追加方法,将一些情况排除(上述添加的是excludeProperty("xxx"))
excludeZeroes(); 排除值为0的属性
excludePreperty("xxx") 排除xxx的属性的条件
ignoreCase() 忽略大小写比较
enableLike() 使用模糊查询
如果要查询所属部门是SALES的员工有哪些,因为部门名字是在dept表中,而结果是在emp表的内容,所以需要使用
到表连接查询:
Criteria crit = session.createCriteria(Emp.class).createCriteria("dept").add(Restrictions.eq
("d_name","SALES"));
第二次可以理解为表连接,查询的是Emp数据,条件是dept里的d_name等于SALES
同理也可以使用主键和外键查询:session.createCriteria(Emp.class).add(Restrictions.eq
("dept.d_id",10));
Projections类的聚合函数
avg() 平均值
count() 出现的次数
countDistinct() 不重复值的数量
max() 最大值
min() 最小值
sum() 总和
例子:计算出现次数
Criteria crit = session.createCriteria(Citizen2.class);
crit.setProjection(Projections.count("CAge"));
Integer count = (Integer) crit.uniqueResult();
System.out.println(count);
例子:当计算的比较多的时候,利用ProjectionList装进去
Criteria crit = session.createCriteria(Citizen2.class);
ProjectionList projList = Projections.projectionList();
projList.add(Projections.max("CAge"));
projList.add(Projections.min("CAge"));
crit.setProjection(projList);
Object[] count = (Object[]) crit.uniqueResult();
System.out.println(count[0]+""+count[1]);
DetachedCriteria的使用(分离的Criteria,可用于不同条件下的查询,复用性高)
//创建DetachedCriteria查询规则,通过forClass方法创建
DetachedCriteria dc = DetachedCriteria.forClass(Citizen2.class);
//添加条件
dc.add(Restrictions.between("CAge", 18, 20));
dc.add(Restrictions.ilike("CName", "%i%"));
//开启第一个会话
Session session = HibernateSessionFactory.getSession();
Transaction tx = session.beginTransaction();
//通过DetachedCriteria得到Criteria对象,参与活动的是session
Criteria crit = dc.getExecutableCriteria(session);
List<Citizen2> list = crit.list();
for (Citizen2 citizen2 : list) {
System.out.println(citizen2.getCAge()+citizen2.getCId
()+citizen2.getCAddress());
}
tx.commit();
//关闭第一个会话
HibernateSessionFactory.closeSession();
//重新打开一个会话
Session session2 = HibernateSessionFactory.getSession();
Transaction tx2 = session2.beginTransaction();
//检测是否是同一个会话,false表示不是一个
System.out.println(session==session2);
//通过DetachedCriteria得到Criteria对象,参与活动的是session
Criteria cri2 = dc.getExecutableCriteria(session2);
cri2.setProjection(Projections.sum("CAge"));
//再次得到查询
Integer ob = (Integer)cri2.uniqueResult();
System.out.println(ob);
//关闭第二个会话
tx2.commit();
HibernateSessionFactory.closeSession();
当然,还可以用于子查询
DetachedCriteria avg = DetachedCriteria.forClass(Emp.class).setProjection
(Property.forName("sal").avg());
//查询工资高于平均工资的员工
List<Emp> emps = session.createCriteria(Emp.class).add(Property.forName('sal').gt
(avg)).list();
三、SQL:Structured Query Language 这是Hibernate提供的原生的SQL查询方式,支持使用SQL语句的
方式查询数据库
//查询表的全部参数,利用addEntity(Citizen2.class)方法转换为实体对象
Query q = session.createSQLQuery("select * from citizen2").addEntity
(Citizen2.class);
//.addScalar("c_id",Integer);用于查询结果和标量值
List<Citizen2> n = q.list();
for (Citizen2 citizen2 : n) {
System.out.println(citizen2.getCName());
}
ORM实体映射
OOP持久化操作
用户通过框架提供的save()、update()、delete()进行增删改等操作
用户调用框架提供的hql或者criteria查询语言、本地SQL查询进行查询操作
配置hibernate环境
第一步:
链接数据库、创建数据源、把链接数据库的信息写在xml配置文件中(hibernate.cfg.xml),如用户名、密码、链
接字符串、驱动类
例(Mysql+Hibernate3.3):
<?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>
<!-- 数据库方言,让框架匹配其平台 -->
<!-- org.hibernate.dialet.Oracle10gDialect -->
<!-- 上方为oracle、下方为mysql、且各个版本有细微差别 -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 链接数据库的url -->
<property name="connection.url">jdbc:mysql://127.0.0.1:3306/lai</property>
<!-- 链接数据库的用户名 -->
<property name="connection.username">root</property>
<!-- 链接数据库的密码 -->
<property name="connection.password">root</property>
<!-- 数据库的JDBC驱动 -->
<!-- oracle.jdbc.driver.OracleDriver -->
<!-- 上方为oracle、下方为mysql -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- 在控制台运行时生成的sql语句,默认没有这一项 -->
<property name="show_sql">true</property>
<!-- 在控制台输出格式化的sql语句 -->
<property name="format_sql">true</property>
<!-- 在myeclipse上链接的工程 -->
<property name="myeclipse.connection.profile">lai</property>
<!-- 映射配置文件 -->
<mapping resource="entity/xw.hbm.xml"/>
</session-factory>
</hibernate-configuration>
第二步:
配置映射文件,一般映射文件命名<tablename>+.hbm.xml
例(xw.hbm.xml):
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<!-- name一般表示持久化类的全限定名(包名+类名) -->
<!-- table表示持久化对应的数据库表名 -->
<!-- catalog表示数据库名称 -->
<class name="id" table="xw" catalog="lai">
<!-- name表示持久化类属性名称 -->
<!-- type表示持久化类属性的类型 -->
<id name="XId" type="java.lang.Integer">
<!-- 表示持久化类对应的数据库表字段的名称 -->
<column name="x_id" />
<!-- generator是id元素的子元素,表示主键生成策略,本例是assigned -->
<generator class="assigned"></generator>
<!-- 常用的生成策略有
assigned 主键由应用程序生成或者用户提供,无需Hibernate干预
increment 对类型为long、short、int的类型数据按数值顺序递增,增值为1
identity 采用数据库提供的主键生成机制,如SQL Server、DB2、Mysql支持
标识符
sequence 采用数据库提供的sequence机制生成主键.如Oracle数据库(序号)
native 由Hibernate根据底层数据库自行判断采用何种主键生成策略
-->
</id>
<!-- name表示持久化类属性名称 -->
<!-- type表示持久化类属性的类型 -->
<property name="XTitle" type="java.lang.String">
<!-- 表示持久化类对应的数据库表字段的名称 -->
<column name="x_title" length="320" />
<!-- column元素常见的属性有
name 表示字段的名称
length 表示字段的长度
not-null 表示是否可以为空
default 表示默认的值
-->
</property>
<property name="XText" type="java.lang.String">
<column name="x_text" length="3200" />
</property>
<property name="XData" type="java.lang.String">
<column name="x_data" length="320" />
</property>
<property name="XFang" type="java.lang.String">
<column name="x_fang" length="320" />
</property>
</class>
</hibernate-mapping>
第三步:
使用Hibernate完成持久化操作
先构建工具类,让其管理session和SessionFactory HibernateSessionFactory.java
package tools;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
public class HibernateSessionFactory {
//创建安全线程,建立本地线程对象
private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
private static org.hibernate.SessionFactory sessionFactory;
private static Configuration configuration = new Configuration();
//指定配置文件
private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml";
static {
try {
configuration.configure(CONFIG_FILE_LOCATION);
sessionFactory = configuration.buildSessionFactory();
} catch (Exception e) {
System.err.println("%%%% 会话工厂创建失败 %%%%");
e.printStackTrace();
}
}
//私有方法,限制new方法实例化
private HibernateSessionFactory() {
}
//返回会话对象session
public static Session getSession() throws HibernateException {
Session session = (Session) threadLocal.get();
if (session == null || !session.isOpen()) {
//为空时重新创建
if (sessionFactory == null) {
try {
configuration.configure(CONFIG_FILE_LOCATION);
sessionFactory = configuration.buildSessionFactory();
} catch (Exception e) {
System.err.println("%%%% 会话工厂创建失败 %%%%");
e.printStackTrace();
}
}
session = (sessionFactory != null) ? sessionFactory.openSession()
: null;
threadLocal.set(session);
}
return session;
}
//关闭会话实例
public static void closeSession() throws HibernateException {
Session session = (Session) threadLocal.get();
threadLocal.set(null);
if (session != null) {
session.close();
}
}
//获取会话工厂的方法
public static org.hibernate.SessionFactory getSessionFactory() {
return sessionFactory;
}
//提供路径的方法,重新指定值
public static void setConfigFile(String configFile) {
HibernateSessionFactory.CONFIG_FILE_LOCATION = configFile;
sessionFactory = null;
}
//获取重新指定路径的configuration对象
public static Configuration getConfiguration() {
return configuration;
}
}
第四步:直接使用
Session session = HibernateSessionFactory.getSession();
Transaction tx = session.beginTransaction();
xw xws= new xw(null, "奇了", "hibernate", "可以添加", "访问量");
session.save(xws);
tx.commit();
HibernateSessionFactory.closeSession();
Hibernate:
select
max(x_id)
from
xw
Hibernate:
insert
into
lai.xw
(x_title, x_text, x_data, x_fang, x_id)
values
(?, ?, ?, ?, ?)
控制台可以看出,hibernate先查询出最大id,再通过最大id进行添加
(查)
根据主键加载对象:
Object get(Class class,Serializable id)方法:
如果为空,则返回null 即时加载
Object load(Class class,Serializable id)方法
如果为空,则抛出异常:org.hibernate.ObjectNotFoundException 延迟加载(可通过lazy改变,变成立即
加载)
(增)
xw xws = new xw(null, "奇了", "hibernate", "可以添加", "访问量");
session.save(xws);
(改)
xw xws = (xw) session.get(xw.class, new Integer(2));
xws.setXTitle("我是新的title");
(删)
xw xws = (xw) session.get(xw.class, new Integer(2));
session.delete(xws);
Hibernate中java对象的三种形态
瞬时状态(Transient) 持久状态(Persistent) 游离状态
(Detached)
xw xws = new xw(null, "奇了", "hibernate", "可以添加", "访问量");
当前属于瞬时状态,它和数据库中的数据没有任何关联
xw xws = (xw) session.get(xw.class, new Integer(2));
session.delete(xws);
当前属于持久状态,session会持续跟踪和管理这些对象,适当的时机,会提交数据,由hibernate固化到数据库中
xw xws= new xw(null, "奇了", "hibernate", "可以添加", "访问量");
session.save(xws);
tx.commit();
HibernateSessionFactory.closeSession();
当前属于游离状态,session关闭后,session实例失效,其从属的持久化对象xws变为游离状态
xw xws= new xw(null, "奇了", "hibernate", "可以添加", "访问量");
session.save(xws);
tx.commit();
session.delete(xws); //游离状态下的xws,可在提交数据后,进行删除游离对象
HibernateSessionFactory.closeSession();
刷新缓存机制:session.flush();
该方法在tx.commit();提交事务时默认调用.无需显示调用,主要用于刷新缓存,执行这些SQL语句,却不提交,所
以不会生效.储存过程.
数据更新的方法:
1、update()用于对游离的对象进行数据库更新操作,如没有OID,则报错
2、saveOrUpdate()如果传入的参数是瞬时状态,则调用save(),反之调用update().
瞬时时,如果存在,则报错org.hibernate.NonUniqueObjectException
3、merge()意为合并,如果该对象存在,则update(),反之save()
hibernate关系映射:
-------------------------------------BIN一对多关联映射BIN----------------------------------------
outer-join:分别是true,false,auto,默认是 auto。true: 表示使用外连接抓取关联的内容
fetch:来源查询fetch="select"
cascade:用于指定如何操纵与当前对象关联的其他对象
none:(默认值)忽略其他关联对象
save-update:当调用save()、update()、saveOrUpdate()方法来保存或更新当前对象时,级联保
存所有关联的瞬时状态和更新所有关联的游离状态
delete:当调用delete()方法删除当前对象时,同时级联删除所有关联对象
all:包含save-updata和delete的行为
all-delete-orphan:包含all及删除当前对象原有关联的"孤立"数据
inverse控制方向反转,如果为false,则为一方维护,反之由多方维护
一、单向多对一关联:
表关系如下:
部门表:id、部门name、city
create table dept(
d_id int auto_increment primary key,
d_name varchar(200),
d_loc varchar(200)
);
员工表:id、员工name、工作、外键
create table emp(
e_id int auto_increment,
e_name varchar(50),
e_job varchar(50),
emp_dept int,
primary key (e_id),
foreign key(emp_dept) references dept (d_id)
);
情景1、在emp类中定义了dept的实例属性,dept中无需定义用于存放emp对象的集合属性
emp.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.emp" table="emp" catalog="lai">
<id name="EId" type="java.lang.Integer">
<column name="e_id" />
<generator class="increment"></generator>
</id>
<many-to-one name="dept" class="entity.dept" fetch="select">
//name:持久化类的属性名;class:持久化类的类型;fetch:来源查询
<column name="emp_dept" />
</many-to-one>
<property name="EName" type="java.lang.String">
<column name="e_name" length="50" />
</property>
<property name="EJob" type="java.lang.String">
<column name="e_job" length="50" />
</property>
</class>
</hibernate-mapping>
dept.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.dept" table="dept" catalog="lai">
<id name="DId" type="java.lang.Integer">
<column name="d_id" />
<generator class="increment"></generator>
</id>
<property name="DName" type="java.lang.String">
<column name="d_name" length="200" />
</property>
<property name="DLoc" type="java.lang.String">
<column name="d_loc" length="200" />
</property>
</class>
</hibernate-mapping>
dept.java
private Integer DId;
private String DName;
private String DLoc;
emp.java
private Integer EId;
private dept dept;
private String EName;
private String EJob;
运行的java
dept Dept = new dept("bumen", "wuhan");
emp Emp1 = new emp(Dept, "zhangsan", "fangniu");
emp Emp2 = new emp(Dept, "lisi", "fangyang");
session.save(Dept);
session.save(Emp1);
session.save(Emp2);
运行结果:即使先save1、2,最后运行save(Dept),也能完成,多使用了updata语句,充分体现了面向对象语言的通
用性
Hibernate:select max(d_id) from dept
Hibernate:select max(e_id) from emp
Hibernate:insert into lai.dept (d_name, d_loc, d_id) values (?, ?, ?)
Hibernate:insert into lai.emp (emp_dept, e_name, e_job, e_id) values (?, ?, ?, ?)
Hibernate:insert into lai.emp (emp_dept, e_name, e_job, e_id) values (?, ?, ?, ?)
二、单向一对多关联:
情景2、dept中定义用于存放emp对象的集合属性,在emp类中无需定义dept的实例属性
Emp.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Emp" table="emp" catalog="lai">
<id name="EId" type="java.lang.Integer">
<column name="e_id" />
<generator class="increment"></generator>
</id>
<property name="EName" type="java.lang.String">
<column name="e_name" length="50" />
</property>
<property name="EJob" type="java.lang.String">
<column name="e_job" length="50" />
</property>
</class>
</hibernate-mapping>
Dept.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Dept" table="dept" catalog="lai">
<id name="DId" type="java.lang.Integer">
<column name="d_id" />
<generator class="increment"></generator>
</id>
<property name="DName" type="java.lang.String">
<column name="d_name" length="200" />
</property>
<property name="DLoc" type="java.lang.String">
<column name="d_loc" length="200" />
</property>
<!-- 持久化类的属性名 -->
<set name="emps">
<key>
<column name="emp_dept" />
<!-- 外键的字段名称 -->
</key>
<one-to-many class="entity.Emp" />
<!-- 多的持久化类 -->
</set>
</class>
</hibernate-mapping>
Dept.java
private Integer DId;
private String DName;
private String DLoc;
private Set<Emp> emps = new HashSet<Emp>(0);
Emp.java
private Integer EId;
private String EName;
private String EJob;
运行的java
Dept dept = new Dept("Abumen", "baijin");
Emp emp1 = new Emp("zs", "cs");
Emp emp2 = new Emp("ls", "fn");
dept.getEmps().add(emp1);
dept.getEmps().add(emp2);
session.save(dept);
session.save(emp1);
session.save(emp2);
运行结果:无论先运行那一方运行,都会多出update语句
Hibernate:select max(d_id) from dept
Hibernate:select max(e_id) from emp
Hibernate:insert into lai.dept (d_name, d_loc, d_id) values (?, ?, ?)
Hibernate:insert into lai.emp (e_name, e_job, e_id) values (?, ?, ?)
Hibernate:insert into lai.emp (e_name, e_job, e_id) values (?, ?, ?)
Hibernate:update lai.emp set emp_dept=? where e_id=?
Hibernate:update lai.emp set emp_dept=? where e_id=?
三、双向一对多关联:
情景3、dept中定义用于存放emp对象的集合属性,在emp类中定义dept的实例属性(结合上两者)
Emp.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Emp" table="emp" catalog="lai">
<id name="EId" type="java.lang.Integer">
<column name="e_id" />
<generator class="increment"></generator>
</id>
<many-to-one name="dept" class="entity.Dept" fetch="select">
<column name="emp_dept" />
</many-to-one>
<property name="EName" type="java.lang.String">
<column name="e_name" length="50" />
</property>
<property name="EJob" type="java.lang.String">
<column name="e_job" length="50" />
</property>
</class>
</hibernate-mapping>
Dept.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Dept" table="dept" catalog="lai">
<id name="DId" type="java.lang.Integer">
<column name="d_id" />
<generator class="increment"></generator>
</id>
<property name="DName" type="java.lang.String">
<column name="d_name" length="200" />
</property>
<property name="DLoc" type="java.lang.String">
<column name="d_loc" length="200" />
</property>
<!-- inverse控制方向反转,如果为false,则为一方维护,反之由多方维护 -->
<set name="emps" inverse="true" cascade="save-update">
<!-- cascade:用于指定如何操纵与当前对象关联的其他对象
none:(默认值)忽略其他关联对象
save-update:当调用save()、update()、saveOrUpdate()方法来保存或更新当前对象时,级联保
存所有关联的瞬时状态和更新所有关联的游离状态
delete:当调用delete()方法删除当前对象时,同时级联删除所有关联对象
all:包含save-updata和delete的行为
all-delete-orphan:包含all及删除当前对象原有关联的"孤立"数据
-->
<key>
<column name="emp_dept" />
</key>
<one-to-many class="entity.Emp" />
</set>
</class>
</hibernate-mapping>
Dept.java
private Integer DId;
private String DName;
private String DLoc;
private Set<Emp> emps = new HashSet<Emp>(0);
Emp.java
private Integer EId;
private Dept dept;
private String EName;
private String EJob;
运行的java
Dept dept = new Dept("部门1", "anhui");
Emp emp = new Emp(dept,"1", "2");
Emp emps = new Emp(dept,"1", "22222");
dept.getEmps().add(emp);
dept.getEmps().add(emps);
session.save(dept);
运行结果:添加Dept的同时,还能自动添加Emp对象
Hibernate:select max(d_id) from dept
Hibernate:select max(e_id) from emp
Hibernate:insert into lai.dept (d_name, d_loc, d_id) values (?, ?, ?)
Hibernate:insert into lai.emp (e_name, e_job, e_id) values (?, ?, ?)
Hibernate:insert into lai.emp (e_name, e_job, e_id) values (?, ?, ?)
情景4、删除Dept对象,同时删除关联的Emp对象
让inverse="true" cascade="delete"
运行的java
Dept dept = (Dept) session.load(Dept.class, new Integer(17));
session.delete(dept);
运行结果:删除Dept对象,和关联的Emp对象
Hibernate:select dept0_.d_id as d1_0_0_,dept0_.d_name as d2_0_0_,dept0_.d_loc as
d3_0_0_ from lai.dept dept0_ where dept0_.d_id=?
Hibernate:select emps0_.emp_dept as emp2_1_,emps0_.e_id as e1_1_,emps0_.e_id as e1_1_0_,
emps0_.emp_dept as emp2_1_0_,emps0_.e_name as e3_1_0_,emps0_.e_job as e4_1_0_ from
lai.emp emps0_ where emps0_.emp_dept=?
Hibernate:delete from lai.emp where e_id=?
Hibernate:delete from lai.emp where e_id=?
Hibernate:delete from lai.dept where d_id=?
情景5、清空Dept对象下所有关联的Emp对象
方式一、多方数据的外键列设为null,变成孤立数据
让inverse="false",且不设置cascade
运行的java
Dept dept = (Dept) session.load(Dept.class, new Integer(27));
dept.getEmps().clear();
运行结果:
Hibernate:select dept0_.d_id as d1_0_0_,dept0_.d_name as d2_0_0_,dept0_.d_loc as
d3_0_0_ from lai.dept dept0_ where dept0_.d_id=?
Hibernate:select emps0_.emp_dept as emp2_1_,emps0_.e_id as e1_1_,emps0_.e_id as e1_1_0_,
emps0_.emp_dept as emp2_1_0_,emps0_.e_name as e3_1_0_,emps0_.e_job as e4_1_0_ from
lai.emp emps0_ where emps0_.emp_dept=?
Hibernate:update lai.emp set emp_dept=null where emp_dept=?
方式二、永久删除
让inverse="true" cascade="all-delete-orphan"
运行的java
/**清空Dept对象下所有关联的Emp对象**/
Dept dept = (Dept) session.load(Dept.class, new Integer(27));
dept.getEmps().clear();
/**通过Emp对象,解除双向关联的关系(双向解除+删除)**/
Emp ems = (Emp) session.get(Emp.class, new Integer(2)); //查找对应的id的ems
Dept dept = (Dept) ems.getDept(); //查找对应的部门
ems.setDept(null); //让其变成孤立数据
dept.getEmps().remove(ems); //移除它
运行结果:Dept对象下关联的Emp对象全部被删除
Hibernate:select dept0_.d_id as d1_0_0_,dept0_.d_name as d2_0_0_,dept0_.d_loc as
d3_0_0_ from lai.dept dept0_ where dept0_.d_id=?
Hibernate:select emps0_.emp_dept as emp2_1_,emps0_.e_id as e1_1_,emps0_.e_id as e1_1_0_,
emps0_.emp_dept as emp2_1_0_,emps0_.e_name as e3_1_0_,emps0_.e_job as e4_1_0_ from
lai.emp emps0_ where emps0_.emp_dept=?
Hibernate:delete from lai.emp where e_id=?
-------------------------------------END一对多关联映射END----------------------------------------
-------------------------------------BIN多对多关联映射BIN----------------------------------------
四、多对多关联映射(由于引入了中间表,导致多对多关联性能不佳,避免在设计中大量使用)
表关系如下:
权限表:id、名称
create table privilege(
p_id int auto_increment,
p_name varchar(50),
primary key (p_id)
);
角色表:id、名字
create table role(
r_id int auto_increment,
rname varchar(50),
primary key (r_id)
);
关系映射表:
create table t_privilege_role(
pid int,
rid int,
foreign key(pid) references privilege (p_id),
foreign key(rid) references role (r_id)
);
Privilege.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Privilege" table="privilege" catalog="lai">
<id name="PId" type="java.lang.Integer">
<column name="p_id" />
<generator class="increment"></generator>
</id>
<property name="PName" type="java.lang.String">
<column name="p_name" length="50" />
</property>
<!-- 维护方反转,映射表, 在下方key和manytomany里的对应的数据,默认位于entity.Privilege-->
<set name="TPrivilegeRoles" table="t_privilege_role" inverse="true">
<key>
<!-- 在映射表中名称为pid,非空 -->
<column name="pid" not-null="true" />
</key>
<!-- 多对多关联,在entity.Role里(set name)TPrivilegeRoles -->
<many-to-many entity-name="entity.Role">
<!-- 在映射表中的名称为rid,非空 -->
<column name="rid" not-null="true"></column>
</many-to-many>
</set>
</class>
</hibernate-mapping>
Role.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Role" table="role" catalog="lai">
<id name="RId" type="java.lang.Integer">
<column name="r_id" />
<generator class="increment"></generator>
</id>
<property name="rname" type="java.lang.String">
<column name="rname" length="50" />
</property>
<set name="TPrivilegeRoles" table="t_privilege_role" cascade="save-update">
<key>
<column name="rid" not-null="true" />
</key>
<many-to-many entity-name="entity.Privilege">
<column name="pid" not-null="true"></column>
</many-to-many>
</set>
</class>
</hibernate-mapping>
Privilege.java
private Integer PId;
private String PName;
private Set TPrivilegeRoles = new HashSet(0);
Role.java
private Integer RId;
private String rname;
private Set TPrivilegeRoles = new HashSet(0);
运行的java
Role role1 = new Role("会计");
Role role2 = new Role("人事");
Privilege privilege1 = new Privilege("员工信息表");
Privilege privilege2 = new Privilege("查询工资表");
role1.getTPrivilegeRoles().add(privilege2);
role2.getTPrivilegeRoles().add(privilege1);
session.save(role1);
session.save(role2);
结果:
mysql> select * from t_privilege_role;
+------+------+
| pid | rid |
+------+------+
| 1 | 1 |
| 2 | 2 |
+------+------+
2 rows in set (0.00 sec)
mysql> select * from privilege;
+------+-----------------+
| p_id | p_name |
+------+-----------------+
| 1 | 鏌ヨ宸ヨ祫琛? |
| 2 | 鍛樺伐淇℃伅琛? |
+------+-----------------+
2 rows in set (0.00 sec)
mysql> select * from role;
+------+--------+
| r_id | rname |
+------+--------+
| 1 | 浼氳 |
| 2 | 浜轰簨 |
+------+--------+
-------------------------------------END多对多关联映射END----------------------------------------
五、一对一关联映射
表关系如下:
-------------------------------------BIN外键映射BIN----------------------------------------
方法1、外键映射
公民表:id、名字、年龄、男女、归属地
create table Citizenl(
c_id int auto_increment,
c_name varchar(30),
c_age int,
c_gender varchar(2),
c_address varchar(200),
primary key (c_id)
);
身份证表:id、外键、身份证号
create table IDCardl(
I_id int auto_increment,
c_id int,
I_idno varchar(18) unique,
primary key (I_id),
foreign key(c_id) references Citizenl (c_id)
);
Citizenl.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Citizenl" table="citizenl" catalog="lai">
<id name="CId" type="java.lang.Integer">
<column name="c_id" />
<generator class="increment"></generator>
</id>
<property name="CName" type="java.lang.String">
<column name="c_name" length="30" />
</property>
<property name="CAge" type="java.lang.Integer">
<column name="c_age" />
</property>
<property name="CGender" type="java.lang.String">
<column name="c_gender" length="2" />
</property>
<property name="CAddress" type="java.lang.String">
<column name="c_address" length="200" />
</property>
<!-- 将entity.Citizenl内idcardls与entity.Idcardl里citizenl关联 -->
<one-to-one name="idcardls" class="entity.Idcardl" property-ref="citizenl"></one-to-one>
</class>
</hibernate-mapping>
IDCardl.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Idcardl" table="idcardl" catalog="lai">
<id name="IId" type="java.lang.Integer">
<column name="I_id" />
<generator class="increment" />
</id>
<!-- 多对一,entity.Idcardl中citizenl,与entity.Citizenl关联 -->
<many-to-one name="citizenl" class="entity.Citizenl" fetch="select" cascade="all" >
<column name="c_id" unique="true" />
</many-to-one>
<property name="IIdno" type="java.lang.String" not-null="true">
<column name="I_idno" length="18" />
</property>
</class>
</hibernate-mapping>
Citizenl.java
private Integer CId;
private String CName;
private Integer CAge;
private String CGender;
private String CAddress;
private Set<Idcardl> idcardls = new HashSet<Idcardl> (0);
IDCardl.java
private Integer IId;
private Citizenl citizenl;
private String IIdno;
运行的java
Citizenl cit = new Citizenl("张三", 12, "男", "东莞");
Idcardl idc = new Idcardl("421102938271918231");
cit.getIdcardls().add(idc);
idc.setCitizenl(cit);
session.save(idc);
运行结果:
mysql> select * from idcardl;
+------+------+--------------------+
| I_id | c_id | I_idno |
+------+------+--------------------+
| 1 | 1 | 421102938271918231 |
+------+------+--------------------+
1 row in set (0.00 sec)
mysql> select * from Citizenl;
+------+--------+-------+----------+-----------+
| c_id | c_name | c_age | c_gender | c_address |
+------+--------+-------+----------+-----------+
| 1 | 寮犱笁 | 12 | 鐢? | 涓滆帪 |
+------+--------+-------+----------+-----------+
1 row in set (0.00 sec)
-------------------------------------END外键映射END----------------------------------------
-------------------------------------BIN主键映射BIN----------------------------------------
方法2、主键映射
公民表:id(主键加外键)、名字、年龄、男女、归属地
create table Citizen2(
c_id int auto_increment,
c_name varchar(30),
c_age int,
c_gender varchar(2),
c_address varchar(200),
primary key (c_id),
foreign key(c_id) references IDCard2 (I_id)
);
身份证表:id、身份证号
create table IDCard2(
I_id int auto_increment,
I_idno varchar(18) unique,
primary key (I_id)
);
Citizen2.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Citizen2" table="citizen2" catalog="lai">
<id name="CId" type="java.lang.Integer">
<column name="c_id" />
<!-- 根据xxx的外键生成主键 -->
<generator class="foreign">
<param name="property">idcard2</param>
</generator>
</id>
<!-- 当前主键存在一个约束 constrained="true" -->
<!-- 将两个类关联起来 -->
<one-to-one name="idcard2" class="entity.Idcard2" constrained="true" >
</one-to-one>
<property name="CName" type="java.lang.String">
<column name="c_name" length="30" />
</property>
<property name="CAge" type="java.lang.Integer">
<column name="c_age" />
</property>
<property name="CGender" type="java.lang.String">
<column name="c_gender" length="2" />
</property>
<property name="CAddress" type="java.lang.String">
<column name="c_address" length="200" />
</property>
</class>
</hibernate-mapping>
IDCard2.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Idcard2" table="idcard2" catalog="lai">
<id name="IId" type="java.lang.Integer">
<column name="I_id" />
<generator class="increment"></generator>
</id>
<property name="IIdno" type="java.lang.String">
<column name="I_idno" length="18" unique="true" />
</property>
<!-- 关联类 -->
<one-to-one name="citizen2" class="entity.Citizen2" cascade="all"></one-to-one>
</class>
</hibernate-mapping>
Citizen2.java
private Integer CId;
private Idcard2 idcard2;
private String CName;
private Integer CAge;
private String CGender;
private String CAddress;
Idcard2.java
private Integer IId;
private String IIdno;
private Citizen2 citizen2;
运行的java代码
Idcard2 id = new Idcard2("1111111321111");
Citizen2 ci = new Citizen2("mie", 18, "男", "日本");
id.setCitizen2(ci);
ci.setIdcard2(id);
session.save(id);
运行结果:
mysql> select * from IDCard2;
+------+----------------+
| I_id | I_idno |
+------+----------------+
| 2 | 1111111321111 |
| 1 | 11211111321111 |
+------+----------------+
2 rows in set (0.00 sec)
mysql> select * from Citizen2;
+------+--------+-------+----------+-----------+
| c_id | c_name | c_age | c_gender | c_address |
+------+--------+-------+----------+-----------+
| 1 | mie | 18 | 鐢? | 鏃ユ湰 |
| 2 | mie | 18 | 鐢? | 鏃ユ湰 |
+------+--------+-------+----------+-----------+
2 rows in set (0.00 sec)
-------------------------------------END主键映射END----------------------------------------
Hibernate数据加载
加载策略:lazy
类级别:<class ... lazy="true">(默认)true延迟加载||false立即加载
一对多关联级别:<set ... lazy="true">(默认)true延迟加载||false立即加载||extra增强延迟加载
多对一关联级别:<many-to-one ... lazy="proxy">(默认)proxy延迟加载||no-proxy无代理延迟加载||false立
即加载
多对多关联级别:<many-to-many ... lazy="proxy" />(默认)proxy延迟加载||false立即加载
利用load方法加载对象,不会访问表中的select语句,会生成一个对应表的代理类,代理类拥有一个属性,主键。
Dept dept = (Dept)session.load(Dept.class,new Interger(10)); //此时的dept就属于一个代理实例
在session关闭后,对应的代理实例就无法初始化
如果一对多中set标签中采用的是立即加载,那么,对一操作时,同时也会加载多,造成了性能的耗费
只有当dept初始化时,才会访问数据库加载,调用其Set集合:
Set<Emp> emps = dept.getEmps();
Interator it = emps.interator()、size()、isEmpty()、contains();
Hibernate.initialize(emps); //初始化
当使用增强延迟加载的时候:他不会查询所有的emp对象,他会比较聪明的发送聚合函数查询数据的记录数,起到
性能优化的作用
Dept dept = (Dept)session.load(Dept.class,new Interger(10));
Set<Emp> emps = dept.getEmps();
int Count = emps.size();
无代理延迟加载,是指只有遇到代理实例,才开始访问数据库,加载程序
立即加载,逐行加载,贼耗性能
OpenSessionInView模式
在视图层打开session:用户每次请求过程中都保持一个Session对象打开
配置流程:
配置文件中加入
<!-- session绑定到当前线程OpenSessionIn View -->
<property name="hibernate.current_session_context_class">thread</property>
创建过滤器类
public class OpenSessionInViewFilter implements Filter{
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// TODO Auto-generated method stub
Transaction tx = null;
try {
Session session = HibernateSessionFactory.getSessionFactory
().getCurrentSession();
tx=session.beginTransaction();
chain.doFilter(request, response);
//返回响应时提交事务
tx.commit();
} catch (HibernateException e) {
// TODO: handle exception
e.printStackTrace();
tx.rollback();
}finally{
HibernateSessionFactory.closeSession();
}
}
@Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
}
web.xml配置上面的filter
<filter>
<filter-name>openSessionInView</filter-name>
<filter-class>tools.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>openSessionInView</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
实际调用的时候:
//通过id返回该对象的代理类
public class DeptDaoImpl {
public Citizen2 getCitizen2(Integer id){
//这里获取的Session对象就是OpenSessionInViewFilter过滤器中打开的session,无需关闭session,
回到过滤器中会自己关闭
Session session = HibernateSessionFactory.getSessionFactory().getCurrentSession
();
//通过getCurrentSession创建的session会在事务提交后,或事物回滚,自动关闭
return (Citizen2) session .get(Citizen2.class, id);
}
}
Hibernate查询
一、HQL:Hibernate Query Language 语法与SQL类似,但它是面向对象的,SQL是关系型数据
[select/delete/update...][from 实体类][where...][group by ...][having...][order by ...]
例:
String hql = "from Citizen2"; //编写hql语句
Query query = session.createQuery(hql); //创建Query对象
List<Citizen2> idcard2 = query.list(); //得到封装好的结果
System.out.println(idcard2.size()); //打印个数
for (Citizen2 citizen2 : idcard2) {
System.out.println(citizen2.getCAge()); //打印输出对应的属性
}
解析:from Citizen2.其中select部分可以省略,from等关键词可以大小写随意写,但是Citizen2只能这么些,这
表示一个类名.
不允许有大小写的出入,完整的写法,select e from Citizen2 as e,as可以省略,不能写成select * from
Citizen2 e.其中e
表示对象名称,表示查询整个对象
/**执行时遇到了错误antlr.collections.AST.getLine()异常,原因是struts中的antlr2.x过时,和hibernate里
的antlr2.7.6冲突**/
/**解决方法:删除Myeclipse文件夹下/configuration/org.eclipse.osgi下删除,再在/plugins/下搜索
*struts*,用压缩包打开删除掉,防止自动生成**/
带条件查询:
String hql = "from Citizen2 where CAge=?"; //条件语句,这里查询的是对象里的参
数,不是数据库里的
//from Citizen2 e where e.CAge=?也行
Query query = session.createQuery(hql); //创建Query对象
query.setInteger(0, 18); //填充条件,第一个问号,jdbc从1开始
,hql从0开始
//setParameter可填充任意形式的字符,int,String
List<Citizen2> idcard2 = query.list();
for (Citizen2 citizen2 : idcard2) {
System.out.println(citizen2.getCAddress());
}
模糊查询(链式写法):
String hql = "from Citizen2 where CName like ? and CAge>? ";
Query query = session.createQuery(hql);
List<Citizen2> cit = query.getString(0,"%运%"),setInteger(1,20).list();
也可以用名字占位(先后顺序可以打乱,参数前面加":"):
String hql = "from Citizen2 where CName like :name and CAge> :age ";
Query query = session.createQuery(hql);
List<Citizen2> cit = query.getString("name","%运%"),setInteger("age",20).list();
主键查询(你确定只有一个结果值时):
String hql = "from Citizen2 where CName like ? and CAge>? ";
Query query = session.createQuery(hql);
Citizen2 cit = query.getString(0,"%运%"),setInteger(1,20).uniqueResult();
投影查询(说的辣么高级,其实就是一般的查询列,最后用Object[]封装而已,类似数组调用):
String hql = "select CId,CName from Citizen2";
Query query = session.createQuery(hql);
List<Object[]> idcard2 = query.list();
for (Object[] obj : idcard2) {
System.out.println(obj[0]+""+obj[1]);
}
返回的是部分值,和上面不同的是List<e>类型,弊端在于需要创建对应的构造函数(new ...)
String hql = "select new Citizen2(CId,CName) from Citizen2";
Query query = session.createQuery(hql);
List<Citizen2> idcard2 = query.list();
for (Citizen2 citizen2 : idcard2) {
System.out.println(citizen2.getCName()+" "+citizen2.getCId());
}
排序(默认情况下,按照升序顺序排序):下面是降序排序(order by e.CId desc)
String hql = "select e from Citizen2 e order by e.CId desc";
Query query = session.createQuery(hql);
List<Citizen2> idcard2 = query.list();
for (Citizen2 citizen2 : idcard2) {
System.out.println(citizen2.getCName()+" "+citizen2.getCId());
}
分页(setFirstResult(n),setMaxResults(m))
String hql ="from Citizen2";
Query query = session.createQuery(hql);
//setFirstResult(0)设置第一条记录的开始位置,这里从0开始.setMaxResults(5):设置每页
显示的大小
query.setFirstResult(0).setMaxResults(5);//查询结果1,2,3,4,5
List<Citizen2> cit = query.list();
for (Citizen2 citizen2 : cit) {
System.out.println(citizen2.getCId());
}
聚合函数(MYSQL中与HQL中对比)
mysql> select count(*) from Citizen2; String hql ="select count(e) from Citizen2 e";
+----------+ //这里第一个e可以换成*或者其他参数,如CId···
| count(*) | Query query = session.createQuery(hql);
+----------+
| 10 | Long count = (Long)query.uniqueResult();
+----------+
1 row in set (0.00 sec) System.out.println(count);结果都是10
mysql> select min(c_id) from Citizen2; String hql ="select max(CId),min(CId),avg(CId)
from Citizen2 e";
+-----------+
| min(c_id) | Query query = session.createQuery(hql);
+-----------+
| 1 | Object[] count = (Object[])query.uniqueResult();
+-----------+
1 row in set (0.00 sec) for (int i = 0; i < count.length; i++) {
System.out.println(count[i]+"\t");
}
内链接:inner join||join
迫切内链接:inner join fetch||join fetch
左链接(迫切):left outer join (fetch)||left join (fetch)
右链接(迫切):right outer join (fetch) || right join
当然HQL还支持分组查询、子查询、表连接(拼接)等,不细细讲了
Double d = 2.1111;//在制作商场网站时,需要制作Double调换,将Double转换精度
new DecimalFormat("0.000").format(d);
二、QBC:Query By Criteria 是一组API提供了完全面向对象的接口、类、方法
专用于对SQL不太熟悉的开发者,主要使用到了Criteria对象,使用add()方法加入查询条件,使用list()方法执行
查询语句.设置条件,
用的比较多的是Restrictions类,而不是Expression类
例子:查询该表
Criteria crit = session.createCriteria(Citizen2.class);
List<Citizen2> list = crit.list();
for (Citizen2 citizen2 : list) {
System.out.println(citizen2.getCName());
}
例子:排序(传入的一样是类中字段,不是表中字段)
Criteria crit = session.createCriteria(Citizen2.class);
crit.addOrder(Order.desc("CId"));
List<Citizen2> list = crit.list();
for (Citizen2 citizen2 : list) {
System.out.println(citizen2.getCName());
}
例子:分页查询(和HQL的分页类似,使用了setFirstResult()、setMaxResults()方法)
Criteria crit = session.createCriteria(Citizen2.class);
crit.setFirstResult(0).setMaxResults(3);
List<Citizen2> list = crit.list();
for (Citizen2 citizen2 : list) {
System.out.println(citizen2.getCName());
}
例子:条件查询(年龄等于22的)
Criteria crit = session.createCriteria(Citizen2.class);
crit.add(Restrictions.eq("CAge", 22));
List<Citizen2> list = crit.list();
for (Citizen2 citizen2 : list) {
System.out.println(citizen2.getCName());
}
Restrictions查询常用方法:
Restrictions.eq() 对应SQL的等于
Restrictions.allEq() 使用Map,对应多个相等的值对比
Restrictions.gt() 对应的SQL大于
Restrictions.ge() 对应的SQL大于等于
Restrictions.lt() 对应的SQL小于
Restrictions.le() 对应的小于等于
Restrictions.between() 对应的between子句
Restrictions.like() 对应的SQL的like子句
Restrictions.in() 对应的SQL的in子句
Restrictions.and() 对应的SQL的and子句
Restrictions.or() 对应的SQL的or子句
Restrictions.not() 对应的SQL的not子句
Restrictions.disjunction() 针对三个及三个以上的or或and条件查询(如下:)
Criteria crit = session.createCriteria(Citizen2.class).add(Restrictions.disjunction().add
(Restrictions.gt("",""))
.add(Restrictions.ge("","")).add(Restrictions.eq("","")));
Restrictions.conjunction() 针对三个或者三个以上的and操作,将上述改成这个方法即可
Example查询(主要用于查询条件较多的时候,会把查询条件封装成一个类):
例子:
Citizen2 cit = new Citizen2();
cit.setCAge(22);
cit.setCName("乐运来");
cit.setCAddress("武汉市");
Criteria crit = session.createCriteria(Citizen2.class);
List<Citizen2> list = crit.add(Example.create(cit)).list();
for (Citizen2 citizen2 : list) {
System.out.println(citizen2.getCId()+citizen2.getCAddress());
}
//List<Citizen2> list = crit.add(Example.create(cit).excludeProperty
("CName")).list();
还可以后面追加方法,将一些情况排除(上述添加的是excludeProperty("xxx"))
excludeZeroes(); 排除值为0的属性
excludePreperty("xxx") 排除xxx的属性的条件
ignoreCase() 忽略大小写比较
enableLike() 使用模糊查询
如果要查询所属部门是SALES的员工有哪些,因为部门名字是在dept表中,而结果是在emp表的内容,所以需要使用
到表连接查询:
Criteria crit = session.createCriteria(Emp.class).createCriteria("dept").add(Restrictions.eq
("d_name","SALES"));
第二次可以理解为表连接,查询的是Emp数据,条件是dept里的d_name等于SALES
同理也可以使用主键和外键查询:session.createCriteria(Emp.class).add(Restrictions.eq
("dept.d_id",10));
Projections类的聚合函数
avg() 平均值
count() 出现的次数
countDistinct() 不重复值的数量
max() 最大值
min() 最小值
sum() 总和
例子:计算出现次数
Criteria crit = session.createCriteria(Citizen2.class);
crit.setProjection(Projections.count("CAge"));
Integer count = (Integer) crit.uniqueResult();
System.out.println(count);
例子:当计算的比较多的时候,利用ProjectionList装进去
Criteria crit = session.createCriteria(Citizen2.class);
ProjectionList projList = Projections.projectionList();
projList.add(Projections.max("CAge"));
projList.add(Projections.min("CAge"));
crit.setProjection(projList);
Object[] count = (Object[]) crit.uniqueResult();
System.out.println(count[0]+""+count[1]);
DetachedCriteria的使用(分离的Criteria,可用于不同条件下的查询,复用性高)
//创建DetachedCriteria查询规则,通过forClass方法创建
DetachedCriteria dc = DetachedCriteria.forClass(Citizen2.class);
//添加条件
dc.add(Restrictions.between("CAge", 18, 20));
dc.add(Restrictions.ilike("CName", "%i%"));
//开启第一个会话
Session session = HibernateSessionFactory.getSession();
Transaction tx = session.beginTransaction();
//通过DetachedCriteria得到Criteria对象,参与活动的是session
Criteria crit = dc.getExecutableCriteria(session);
List<Citizen2> list = crit.list();
for (Citizen2 citizen2 : list) {
System.out.println(citizen2.getCAge()+citizen2.getCId
()+citizen2.getCAddress());
}
tx.commit();
//关闭第一个会话
HibernateSessionFactory.closeSession();
//重新打开一个会话
Session session2 = HibernateSessionFactory.getSession();
Transaction tx2 = session2.beginTransaction();
//检测是否是同一个会话,false表示不是一个
System.out.println(session==session2);
//通过DetachedCriteria得到Criteria对象,参与活动的是session
Criteria cri2 = dc.getExecutableCriteria(session2);
cri2.setProjection(Projections.sum("CAge"));
//再次得到查询
Integer ob = (Integer)cri2.uniqueResult();
System.out.println(ob);
//关闭第二个会话
tx2.commit();
HibernateSessionFactory.closeSession();
当然,还可以用于子查询
DetachedCriteria avg = DetachedCriteria.forClass(Emp.class).setProjection
(Property.forName("sal").avg());
//查询工资高于平均工资的员工
List<Emp> emps = session.createCriteria(Emp.class).add(Property.forName('sal').gt
(avg)).list();
三、SQL:Structured Query Language 这是Hibernate提供的原生的SQL查询方式,支持使用SQL语句的
方式查询数据库
//查询表的全部参数,利用addEntity(Citizen2.class)方法转换为实体对象
Query q = session.createSQLQuery("select * from citizen2").addEntity
(Citizen2.class);
//.addScalar("c_id",Integer);用于查询结果和标量值
List<Citizen2> n = q.list();
for (Citizen2 citizen2 : n) {
System.out.println(citizen2.getCName());
}