hibernate 1
博客专区 > frankbak 的博客 > 博客详情
hibernate 1
frankbak 发表于3年前
hibernate 1
  • 发表于 3年前
  • 阅读 9
  • 收藏 0
  • 点赞 0
  • 评论 0
第1课 课程内容
1、	HelloWorld
a)	Xml
b)	Annotction
2、	Hibernate原理模拟-什么是O/RMapping以及为什么要有O/RMapping
3、	常风的O/R框架
4、	Hibernate基础配置
5、	Hibernate核心接口介绍
6、	对象的三种状态
7、	ID生成策略
8、	关系映射
9、	Hibernate查询(HQL)
10、	在Struts基础上继续完美BBS2009
11、	性能优化
12、	补充话题


结合struts与hibernate后程序的架构如下:

Hibernate UML图


hibernate下载网站

http://www.hibernate.org

Download hibernate-search-4.0.0.Beta2-dist.zip (25.3 MB)   ----->说明 Beta 版本是测试版本,不能正常使用


hibernate-distribution-3.6.8.Final-dist.zip      以zip结尾的是windows下的版本    final表示版本号 正式版

hibernate-distribution-3.6.8.Final-dist.tar.gz    以gz结尾的是linux下的版本


compatibility matrix  兼容性矩阵  

例如: 就是你下载的 hibernate core 版本是3.2.6 GA 对应的Annotations注解包就应该是2.2.x, 3.3.x

下载的是3.3.2对应的就是3.4.x :     不过下面有好消息说明的是3.5.x 过后会把 core 、Annotations、EntityManager 包放在一起

please note that as of 3.5.x hibernate core,hibernate annotations and hibernate entitymanager are all versioned and released together whcih greatly simplifies this matrix

hibernate 做日志的时候有到的是  SLF4J

http://www.slf4j.org/


hibernate-annotations-3.4.0.GA  中文版文档目录

D:\java rj\ssh\hibernate\hibernate-annotations-3.4.0.GA\doc\reference\zh_cn\html_single\index.html     


hibernate-(distribution)core 中文版文档目录

D:\java rj\ssh\hibernate\hibernate-distribution-3.3.2.GA\documentation\manual\zh-CN\html_single\index.html

——————————————————

第3课 风格

1、  先脉络,后细节

2、  先操作、后原理

3、  重Annotation,轻xml配置文件

a)        JPA (可以认为EJB3的一部分)

b)        Hibernate– extension

 

第4课 资源

1、  http://www.hibernate.org

a)        hibernate-distribution-3.3.2.GA-dist.zip

b)        hibernate-annotations-3.4.0.GA.zip

c)         slf4j-1.5.10.zip    (hibernate内部日志用)

2、  hibernatezh_CN文档

3、  hibernateannotateon references

 

第5课 环境准备

1、  下载hibernate3.3.2

2、  下载hibernate-annotations-3.4.0

3、  注意阅读hibernate compatibility matrix

4、  下载slf4j 1.5.8

 

第6课 第一个示例Hibernate HelloWorld

1、  建立新的java项目,名为hibernate_0100_HelloWorld

2、  学习建立User-liberary-hibernate,并加入相应的jar包

a)        项目右键-build path-configure build path-add library

b)        选择User-library ,在其中新建library,命名为hibernate

c)         在该library中加入hibernate所需的jar名

                        i.             Hibernatecore

                       ii.             /lib/required

                     iii.             Slf-nopjar

3、  引入mysql的JDBC驱动名

4、  在mysql中建立对应的数据库以及表

a)        Create databasehibernate;

b)        Usehibernate;

c)         Createtable Student (id int primary key, name varchar(20),age int);

5、  建立hibernate配置文件hibernate.cfg.xml

a)        从参考文档中copy

b)        修改对应的数据库连接

c)         注释提暂时不需要的内容

6、  建立Student类

7、  建立Student映射文件Student.hbm.xml

a)        参考文档

8、  将映射文件加入到hibernate.cfg.xml

a)        参考文档

9、  写测试类Main,在Main中对Student对象进行直接的存储测试


第一项目
加入jar文件

先new一个libraries


再加入jar包 Add JARs

bytecode 生成二进制字节码的要的jar包

optional 可选的

required 必须的   (全部导入)


之所以要从新在官网下载是因为

lib目录下只定义了slf4就的api 没有定实现 (就犹如你拿到了接口没有拿到实现) 因此要运行必须到slf4j官网去下载

http://www.slf4j.org/dist/  slf4j 要与hibernate的api名称一致

需要的slf4j下面的包是  slf4j-nop-1.5.8.jar

以上是最原始的hibernate 需要的包,如果还需要annotation的话还需要它的3个包

在项目里面选择如下:

选择项目---> 右键  build path ---> Add Libraries --->User Library

选择hibernate 点击Finish 完成

还需要和数据库建立联系 因此还需要mysql 的一个数据包mysql-connector-java-5.1.18-bin.jar

drop table student;
create database hibernate;
use hibernate;
create table student;
create table student (
	id int primary key,
	name varchar(20),
	age int 
);


<hibernate-mapping package="org.hibernate.tutorial.domain">

    <class name="Event" table="EVENTS">
        <id name="id" column="EVENT_ID">
            <generator class="native"/>
        </id>
        <property name="date" type="timestamp" column="EVENT_DATE"/>
        <property name="title"/>
    </class>

</hibernate-mapping>



class里面的 name指的是类名 而table 是指数据库里面的表名 如果表名与类名一样 可以不写table名 数据库不区分大小写

id 是指主键名 (primay key) column是指可以指定数据库id名 而name是指类名的属性 一样可以不写 column

property 是指类名里面的属性

事例如下:

<hibernate-mapping package="com.demo.hibernate.model">
	<class name="Student">
		<id name="id"></id>
		<property name="name"/>
		<property name="age"/>
	</class>
</hibernate-mapping>

第一个hibernate程序:

//Student 类
package com.demo.hibernate.model;

public class Student {
	private int id;
	private String name;
	private int age;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	
}


<!--  hibernate.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>

        <!-- Database connection settings -->
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="connection.url">jdbc:mysql://localhost/hibernate</property>
        <property name="connection.username">root</property>
        <property name="connection.password">root</property>

        <!-- JDBC connection pool (use the built-in) -->
    	<!--    <property name="connection.pool_size">1</property> --> 

        <!-- SQL dialect -->
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>

        <!-- Enable Hibernate's automatic session context management -->
        <!-- <property name="current_session_context_class">thread</property> -->

        <!-- Disable the second-level cache  -->
        <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>

        <!-- Echo all executed SQL to stdout -->
        <property name="show_sql">true</property>

        <!-- Drop and re-create the database schema on startup -->
        <!-- <property name="hbm2ddl.auto">update</property> -->

        <mapping resource="com/demo/hibernate/model/Student.hbm.xml"/>

    </session-factory>

</hibernate-configuration>


<!-- Student.hbm.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="com.demo.hibernate.model">
	<class name="Student">
		<id name="id"></id>
		<property name="name"/>
		<property name="age"/>
	</class>
</hibernate-mapping>


//StudentTest
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

import com.demo.hibernate.model.Student;


public class StudentTest {
	public static void main(String[] args) {
		Student s = new Student();
		s.setId(1);
		s.setName("s1");
		s.setAge(1);
		
		Configuration cfg = new Configuration();
		SessionFactory sf = cfg.configure().buildSessionFactory();
		Session session = sf.openSession();
		session.beginTransaction();
		session.save(s);
		session.getTransaction().commit();
		session.close();
		sf.close();
	}
}

   

 建立Annotation版本的HellWorld

   注意:要求hibernate3.0版本以后支持

引入annotation jar包


package com.demo.hibernate.model;
import javax.persistence.Entity;
import javax.persistence.Id;

@Entity //实体类
public class Teacher {
	private int id;
	private String name;
	private String title;
	
	@Id  //主键
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}


<!-- hibernate.hbm.xml -->
<mapping class="com.demo.hibernate.model.Teacher"/>


//TeacherTest
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.cfg.Configuration;

import com.demo.hibernate.model.Teacher;

public class TeacherTest {
    public static void main(String[] args) {
        Teacher t = new Teacher();
        t.setId(1);
        t.setName("t1");
        t.setTitle("中级");
        
        Configuration cfg = new AnnotationConfiguration();
        SessionFactory sf = cfg.configure().buildSessionFactory();
        Session session = sf.openSession();
        session.beginTransaction();
        session.save(t);
        session.getTransaction().commit();
        session.close();
        sf.close();
    }
}


 Annotation 与影视文件不一致的有:

1、不需要建立映射文件 

2、hibernate.hbm.xml  里面用.

3、Configuration 里面创建用AnnotationConfiguration()

敲. (点) 提示设置如下: Auto activation triggers for Java . 



第8课 什么是O/R Mapping

一、             定义:

ORM(ObjectRelational Mapping)---是一种为了解决面向对象与关系型数据库存在的互不匹配的现象的技术。简单说:ORM是通过使用描述对象和数据库之间映射的元数据,将Java程序中的对象自动持久化到关系数据中。本质上就是将数据从一种形式转换到另外一种形式。


分层后,上层不需要知道下层是如何做了。

分层后,不可以循环依赖,一般是单向依赖。

 

二、             Hibernate的创始人:

Gavin King

 

三、             Hibernate做什么:

1、    就是将对象模型(实体类)的东西存入关系模型中,

2、    实体中类对应关系型库中的一个表,

3、    实体类中的一个属性会对应关系型数据库表中的一个列

4、    实体类的一个实例会对应关系型数据库表中的一条记录。

%%将对象数据保存到数据库、将数据库数据读入到对象中%%

 

OOA---面向对象的分析、面向对象的设计

OOD---设计对象化

OOP---面向对象的开发

阻抗不匹配---例JAVA类中有继承关系,但关系型数据库中不存在这个概念这就是阻抗不匹配。Hibernate可以解决这个问题

 

四、             Hibernate存在的原因:

1、  解决阻抗不匹配的问题;

2、  目前不存在完整的面向对象的数据库(目前都是关系型数据库);

3、  JDBC操作数据库很繁琐

4、  SQL语句编写并不是面向对象

5、  可以在对象和关系表之间建立关联来简化编程

6、  O/RMapping简化编程

7、  O/RMapping跨越数据库平台

8、  hibernate_0200_OR_Mapping_Simulation

 

五、             Hibernate的优缺点:

1、  不需要编写的SQL语句(不需要编辑JDBC),只需要操作相应的对象就可以了,就可以能够存储、更新、删除、加载对象,可以提高生产效;

2、  因为使用Hibernate只需要操作对象就可以了,所以我们的开发更对象化了;

3、  使用Hibernate,移植性好(只要使用Hibernate标准开发,更换数据库时,只需要配置相应的配置文件就可以了,不需要做其它任务的操作);

4、  Hibernate实现了透明持久化:当保存一个对象时,这个对象不需要继承Hibernate中的任何类、实现任何接口,只是个纯粹的单纯对象—称为POJO对象(最纯粹的对象—这个对象没有继承第三方框架的任何类和实现它的任何接口)

5、  Hibernate是一个没有侵入性的框架,没有侵入性的框架我们一般称为轻量级框架

6、  Hibernate代码测试方便。

 

六、             Hibernate使用范围:

1.       针对某一个对象,简单的将它加载、编辑、修改,且修改只是对单个对象(而不是批量的进行修改),这种情况比较适用;

2.       对象之间有着很清晰的关系(例:多个用户属于一个组(多对一)、一个组有多个用户(一对多));

3.       聚集性操作:批量性添加、修改时,不适合使用Hibernate(O/映射框架都不适合使用);

4.       要求使用数据库中特定的功能时不适合使用,因为Hibernate不使用SQL语句;

 

第9课 Hibernate的重点学习:Hibernate的对象关系映射

一、对象---关系映射模式

l         属性映射;

l         类映射:

l         关联映射:

n         一对一;

n         一对多;

n         多对多。

 

二、常用的O/R映射框架:

1、  Hibernate

2、  ApacheOJB

3、  JDO(是SUN提出的一套标准—Java数据对象)

4、  Toplink(Orocle公司的)

5、  EJB(2.0X中有CMP;3.0X提出了一套“Java持久化API”---JPA)

6、  IBatis(非常的轻量级,对JDBC做了一个非常非常轻量级的包装,严格说不是O/R映射框架,而是基于SQL的映射(提供了一套配置文件,把SQL语句配置到文件中,再配置一个对象进去,只要访问配置文件时,就可得到对象))

7、  JAP(是SUN公司的一套标准)

a)        意愿统一天下



第10课 模拟Hibernate原理(OR模拟)

         我们使用一个项目来完成

         功能:有一个配置文件,文件中完成表名与类名对象,字段与类属性对应起来。

测试驱动开发

 

一、 项目名称

         hibernate_0200_OR_Mapping_Simulation

二、 原代码

Test类:
	public static void main(String[] args) throws Exception{
		
		Student s = new Student();
		s.setId(10);
		s.setName("s1");
		s.setAge(1);
		
		Session session = new Session();//此Session是我们自己定义的Session
		
		session.save(s);
}


Session类
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.util.HashMap;
import java.util.Map;
import com.wjt276.hibernate.model.Student;
public class Session {
	String tableName = "_Student";
	Map<String,String> cfs = new HashMap<String,String>();
	String[] methodNames;//用于存入实体类中的get方法数组
	public Session(){
		cfs.put("_id", "id");
		cfs.put("_name", "name");
		cfs.put("_age", "age");
		methodNames = new String[cfs.size()];
	}
	public void save(Student s) throws Exception{
		String sql = createSQL();//创建SQL串
		Class.forName("com.mysql.jdbc.Driver");
		Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/hibernate","root","root");
		PreparedStatement ps = conn.prepareStatement(sql);
		//
		for(int i = 0; i < methodNames.length; i++){
			Method m = s.getClass().getMethod(methodNames[i]);//返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法
			Class r = m.getReturnType();//返回一个 Class 对象,该对象描述了此 Method 对象所表示的方法的正式返回类型
			if(r.getName().equals("java.lang.String")) {
				//对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。
				//个别参数被自动解包,以便与基本形参相匹配,基本参数和引用参数都随需服从方法调用转换
				String returnValue = (String)m.invoke(s);
				ps.setString(i + 1, returnValue);
			}
			if(r.getName().equals("int")) {
				Integer returnValue = (Integer)m.invoke(s);
				ps.setInt(i + 1, returnValue);
			}
			if(r.getName().equals("java.lang.String")) {
				String returnValue = (String)m.invoke(s);
				ps.setString(i + 1, returnValue);
			}
			System.out.println(m.getName() + "|" + r.getName());
		}		
		ps.executeUpdate();
		ps.close();
		conn.close();
	}
	private String createSQL() {
		String str1 = "";
		int index = 0;
		
		for(String s : cfs.keySet()){
			String v = cfs.get(s);//取出实体类成员属性
			v = Character.toUpperCase(v.charAt(0)) + v.substring(1);//将成员属性第一个字符大写
			methodNames[index] = "get" + v;//拼实体类成员属性的getter方法
			str1 += s + ",";//根据表中字段名拼成字段串
			index ++;
		}
		str1 = str1.substring(0,str1.length() -1);
		String str2 = "";
		//根据表中字段数,拼成?串
		for (int i = 0; i < cfs.size(); i++){	str2 += "?,";}
		str2 = str2.substring(0,str2.length() -1);
		String sql = "insert into " + tableName + "(" + str1 + ")" + " values (" + str2 + ")";
		System.out.println(sql);
		return sql;
	}}



第11课 Hibernate基础配置

一、 提纲

1、  对应项目:hibernate_0300_BasicConfiguration

2、  介绍MYSQL的图形化客户端

3、  Hibernate.cfg.xml:hbm2ddl.auto

a) 先建表还是先建实体类

4、  搭建日志环境并配置显示DDL语句

5、  搭建Junit环境

a) 需要注意Junit的Bug

6、  ehibernate.cfg.xml: show_sql

7、  hibernate.cfg.xml:format_sql

8、  表名和类名不同,对表名进行配置

a) Annotation:@Table

b) Xml:自己查询

9、  字段名和属性相同

a) 默认为@Basic

b) Xml中不用写column

10、    字段名和属性名不同

a) Annotation:@Column

b) Xml:自己查询

11、    不需要psersistence的字段

a) Annotation:@Transient

b) Xml:不写

12、    映射日期与时间类型,指定时间精度

a) Annotation:@Temporal

b) Xml:指定type

13、    映射枚举类型

a) Annotation:@Enumerated

b) Xml:麻烦

14、    字段映射的位置(field或者get方法)

a) Best practice:保持field和get/set方法的一致

15、    @Lob

16、    课外:CLOB BLOB类型的数据存取

17、    课外:Hibernate自定义数据类型

18、    Hibernate类型

 

二、 介绍MYSQL的图形化客户端

这样的软件网络很多,主要自己动手做

三、 Hibernate.cfg.xml:hbm2ddl.auto

在SessionFactory创建时,自动检查数据库结构,或者将数据库schema的DDL导出到数据库. 使用 create-drop时,在显式关闭SessionFactory时,将drop掉数据库schema.取值 validate | update | create | create-drop

四、 搭建日志环境并配置显示DDL语句

我们使用slf接口,然后使用log4j的实现。

1、  首先引入log4j的jar包(log4j-1.2.14.jar),

2、  然后再引入slf4j实现LOG4J和适配器jar包(slf4j-log4j12-1.5.8.jar)

3、  最后创建log4j的配置文件(log4j.properties),并加以修改,只要保留

log4j.logger.org.hibernate.tool.hbm2ddl=debug

五、 搭建Junit环境

1、首先引入Junit 类库 jar包 (junit-4.8.1.jar)

2、在项目名上右键→new→Source Folder→输入名称→finish

3、注意,你对哪个包进行测试,你就在测试下建立和那个包相同的包

4、建立测试类,需要在测试的方法前面加入”@Test”


————————————————————————————————————————————————

<property name="hbm2ddl.auto">create</property>
hibernate.hbm.xml 中创建表的语句(在表中自动创建数据库表)  validate | update | create | create-drop

slf4j(接口)下面一些日志实现



http://logging.apache.org/log4j/1.2/index.html    log4j使用比slf4j比较流行

不过使用的时候需要一个转换器,即slf4j的slf4j-log4j12-1.5.8.jar    而不是( slf4j-log4j12-1.5.8-sources.jar)

hibernate Libraries 中jar包编辑

在hibernate 上面单击右键 --->Build Path —> Configure Build Path —>  Edit 即可进行编辑


D:\javasoft\ssh\hibernate\hibernate-distribution-3.3.2.GA\project\etc\log4j.properties

加入log4j 日志报错,(SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".) 原来是把jar包导入错误应该是slf4j-log4j12-1.5.8.jar

src下面的日志文件         log4j.properties

### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### direct messages to file hibernate.log ###
#log4j.appender.file=org.apache.log4j.FileAppender
#log4j.appender.file.File=hibernate.log
#log4j.appender.file.layout=org.apache.log4j.PatternLayout
#log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### set log levels - for more verbose logging change 'info' to 'debug' ###

log4j.rootLogger=warn, stdout

#log4j.logger.org.hibernate=info
#log4j.logger.org.hibernate=debug

### log HQL query parser activity
#log4j.logger.org.hibernate.hql.ast.AST=debug

### log just the SQL
#log4j.logger.org.hibernate.SQL=debug

### log JDBC bind parameters ###
#log4j.logger.org.hibernate.type=info
#log4j.logger.org.hibernate.type=debug

### log schema export/update ###
log4j.logger.org.hibernate.tool.hbm2ddl=debug

### log HQL parse trees
#log4j.logger.org.hibernate.hql=debug

### log cache activity ###
#log4j.logger.org.hibernate.cache=debug

### log transaction activity
#log4j.logger.org.hibernate.transaction=debug

### log JDBC resource acquisition
#log4j.logger.org.hibernate.jdbc=debug

### enable the following line if you want to track down connection ###
### leakages when using DriverManagerConnectionProvider ###
#log4j.logger.org.hibernate.connection.DriverManagerConnectionProvider=trace


主要是看见ddl 语句

Junit (junit-4.8.jar )

Junit(bug) 测试部提示错误具体信息的时候2种常用的方法

1、用try {} catch(){}

2、main()方法

例子程序如下

package com.demo.hibernate.model;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.cfg.Configuration;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;


public class TeacherTest {
	private static SessionFactory sf = null;
	@BeforeClass
	public static void beforClass() {  
//		try {
			sf = new AnnotationConfiguration().configure().buildSessionFactory();
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
	}
	@Test
	public void testTeacherSave() {
		Teacher t = new Teacher();
		t.setId(1);
		t.setName("t1");
		t.setTitle("中级");
		Session session = sf.openSession();
		session.beginTransaction();
		session.save(t);
		session.getTransaction().commit();
		session.close();
	}
//	public static void main() {
//		beforClass();
//	}
	@AfterClass
	public static void afterClass() {
		sf.close();
	}
}

<property name="format_sql">true</property>
显示更加规范和漂亮的建表语句

如下

10:49:19,563  INFO SchemaExport:226 - Running hbm2ddl schema export
10:49:19,575 DEBUG SchemaExport:242 - import file not found: /import.sql
10:49:19,575  INFO SchemaExport:251 - exporting generated schema to database
10:49:19,577 DEBUG SchemaExport:377 - 
    drop table if exists Student
10:49:19,935 DEBUG SchemaExport:377 - 
    drop table if exists Teacher
10:49:19,968 DEBUG SchemaExport:377 - 
    create table Student (
        id integer not null,
        name varchar(255),
        age integer,
        primary key (id)
    )
10:49:20,012 DEBUG SchemaExport:377 - 
    create table Teacher (
        id integer not null,
        name varchar(255),
        title varchar(255),
        primary key (id)
    )
10:49:20,031  INFO SchemaExport:268 - schema export complete
Hibernate: 
    insert 
    into
        Teacher
        (name, title, id) 
    values
        (?, ?, ?)

1、  表名和类名不同,对表名进行配置

a) Annotation:@Table

b) Xml:自己查询

2、  字段名和属性相同

a) 默认为@Basic

b) Xml中不用写column


映射文件表名指定

<class name="Student" table="_student">

Annotation表名指定

@Table(name="_Teacher")   (import javax.persistence.Table;)

public class Teacher{ }


1、  字段名和属性名不同

a) Annotation:@Column

    @Column(name="_title")
    public String getTitle() {
        return title;
    }


1、  不需要psersistence的字段

a) Annotation:@Transient

b) Xml:不写

//@Transient  隐藏数据库里面的字段
    public String getYouWifeName() {
        return youWifeName;
    }


1、  映射日期与时间类型,指定时间精度

a) Annotation:@Temporal

b) Xml:指定type


一般在注解(@)里面有value 可以不写,直接写后面的值

java类里面的日期一般用 import java.util.Date; 

xml里面   <property name="name" type="date"/>  


@Annotation
    @Temporal(TemporalType.DATE)  //只记录日期
    public Date getDate() {
        return date;
    }


1、  映射枚举类型

a) Annotation:@Enumerated

b) Xml:麻烦

     @Enumerated(EnumType.STRING)
    public ZhiCheng getZhiCheng() {
        return zhiCheng;

    }

public enum ZhiCheng {
    A, B, C
}

第13课 ID主键生成策略

一、 Xml方式

<id>标签必须配置在<class>标签内第一个位置。由一个字段构成主键,如果是复杂主键<composite-id>标签

被映射的类必须定义对应数据库表主键字段。大多数类有一个JavaBeans风格的属性, 为每一个实例包含唯一的标识。<id> 元素定义了该属性到数据库表主键字段的映射。

<id

       name="propertyName"                                          (1)

       type="typename"                                              (2)

       column="column_name"                                         (3)

       unsaved-value="null|any|none|undefined|id_value"             (4)

       access="field|property|ClassName"                            (5)

       node="element-name|@attribute-name|element/@attribute|.">

 

        <generatorclass="generatorClass"/>

</id>

(1) name (可选): 标识属性的名字(实体类的属性)。

(2) type (可选): 标识Hibernate类型的名字(省略则使用hibernate默认类型),也可以自己配置其它hbernate类型(integer, long, short, float,double, character, byte, boolean, yes_no, true_false)

(2) length(可选):当type为varchar时,设置字段长度

(3) column (可选 - 默认为属性名): 主键字段的名字(省略则取name为字段名)。

(4) unsaved-value (可选 - 默认为一个切合实际(sensible)的值): 一个特定的标识属性值,用来标志该实例是刚刚创建的,尚未保存。 这可以把这种实例和从以前的session中装载过(可能又做过修改--译者注) 但未再次持久化的实例区分开来。

(5) access (可选 - 默认为property): Hibernate用来访问属性值的策略。

如果 name属性不存在,会认为这个类没有标识属性。

unsaved-value 属性在Hibernate3中几乎不再需要。

还有一个另外的<composite-id>定义可以访问旧式的多主键数据。 我们强烈不建议使用这种方式。

<generator>元素(主键生成策略)

主键生成策略是必须配置

用来为该持久化类的实例生成唯一的标识。如果这个生成器实例需要某些配置值或者初始化参数, 用<param>元素来传递。

<id name="id"type="long" column="cat_id">

       <generator class="org.hibernate.id.TableHiLoGenerator">

               <param name="table">uid_table</param>

               <param name="column">next_hi_value_column</param>

       </generator>

</id>

所有的生成器都实现org.hibernate.id.IdentifierGenerator接口。 这是一个非常简单的接口;某些应用程序可以选择提供他们自己特定的实现。当然, Hibernate提供了很多内置的实现。下面是一些内置生成器的快捷名字:

increment

用于为long, short或者int类型生成 唯一标识。只有在没有其他进程往同一张表中插入数据时才能使用。 在集群下不要使用。

identity

对DB2,MySQL, MS SQL Server,Sybase和HypersonicSQL的内置标识字段提供支持。 返回的标识符是long, short 或者int类型的。 (数据库自增)

sequence

在DB2,PostgreSQL, Oracle, SAPDB, McKoi中使用序列(sequence), 而在Interbase中使用生成器(generator)。返回的标识符是long, short或者 int类型的。(数据库自增)

hilo

使用一个高/低位算法高效的生成long, short 或者 int类型的标识符。给定一个表和字段(默认分别是 hibernate_unique_key和next_hi)作为高位值的来源。 高/低位算法生成的标识符只在一个特定的数据库中是唯一的。

seqhilo

使用一个高/低位算法来高效的生成long, short 或者 int类型的标识符,给定一个数据库序列(sequence)的名字。

uuid

用一个128-bit的UUID算法生成字符串类型的标识符, 这在一个网络中是唯一的(使用了IP地址)。UUID被编码为一个32位16进制数字的字符串,它的生成是由hibernate生成,一般不会重复。

UUID包含:IP地址,JVM的启动时间(精确到1/4秒),系统时间和一个计数器值(在JVM中唯一)。 在Java代码中不可能获得MAC地址或者内存地址,所以这已经是我们在不使用JNI的前提下的能做的最好实现了

guid

在MS SQL Server 和 MySQL 中使用数据库生成的GUID字符串。

native

根据底层数据库的能力选择identity,sequence 或者hilo中的一个。(数据库自增)

assigned

让应用程序在save()之前为对象分配一个标示符。这是 <generator>元素没有指定时的默认生成策略。(如果是手动分配,则需要设置此配置)

select

通过数据库触发器选择一些唯一主键的行并返回主键值来分配一个主键。

foreign

使用另外一个相关联的对象的标识符。通常和<one-to-one>联合起来使用。

二、 annotateon方式

使用@GeneratedValue(strategy=GenerationType)注解可以定义该标识符的生成策略

Strategy有四个值:

①     、AUTO- 可以是identity column类型,或者sequence类型或者table类型,取决于不同的底层数据库.

相当于native

②     、TABLE- 使用表保存id值

③     、IDENTITY- identity column

④     、SEQUENCE- sequence

注意:auto是默认值,也就是说没有后的参数则表示为auto


1、getCurrentSession()与openSession()的区别?
 * 采用getCurrentSession()创建的session会绑定到当前线程中,而采用openSession()
   创建的session则不会
 * 采用getCurrentSession()创建的session在commit或rollback时会自动关闭,而采用openSession()
   创建的session必须手动关闭
  
2、使用getCurrentSession()需要在hibernate.cfg.xml文件中加入如下配置:
 * 如果使用的是本地事务(jdbc事务)
 <property name="hibernate.current_session_context_class">thread</property>
 * 如果使用的是全局事务(jta事务)
 <property name="hibernate.current_session_context_class">jta</property>


//uuid
<class name="com.demo.hibernate.Student">
		<id name="id">
			<generator class="uuid"></generator>
		</id>
		<property name="name"/>
		<property name="age"/>
	</class>

private String id;  //uuid 的id必须是String类型

//native
<class name="com.demo.hibernate.Student">
		<id name="id">
			<generator class="native"></generator>
		</id>
		<property name="name"/>
		<property name="age"/>
	</class>

    private int id;   /native 的id是int类型  相当于auto_increment


package com.demo.hibernate.model;
import java.util.Date;

import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Id;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;


@Entity //实体类
// @Table(name="_teacher")
public class Teacher {
	private int id;
	private String name;
	private String title;
	private String youWifeName;
	private Date date;
	private ZhiCheng zhiCheng; 
	
	@Enumerated(EnumType.STRING)
	public ZhiCheng getZhiCheng() {
		return zhiCheng;
	}
	public void setZhiCheng(ZhiCheng zhiCheng) {
		this.zhiCheng = zhiCheng;
	}
	//@Temporal(TemporalType.DATE)  //只记录日期
	public Date getDate() {
		return date;
	}
	public void setDate(Date date) {
		this.date = date;
	}
	//@Transient  隐藏数据库里面的字段
	public String getYouWifeName() {
		return youWifeName;
	}
	public void setYouWifeName(String youWifeName) {
		this.youWifeName = youWifeName;
	}
	@Id  //主键
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	//@Column(name="_title")
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}




oracle 表名不允许下划线开头


如果id生成策略使用native 在mysql使用auto_increment , 在oracle 使用sequenceSQL Server 使用 identity

@GeneratedValue
    public int getId() {
        return id;
    } 

相当于xml里面的native

.. 映射主键属性

使用@Id注解可以将实体bean中的某个属性定义为标识符(identifier). 该属性的值可以通过应用自身进行设置, 也可以通过Hiberante生成(推荐).

使用 @GeneratedValue注解可以定义该标识符的生成策略:

  • AUTO - 可以是identity column类型,或者sequence类型或者table类型,取决于不同的底层数据库.

  • TABLE - 使用表保存id值

  • IDENTITY - identity column

  • SEQUENCE - sequence


@GeneratedValue(strategy=GenerationType.IDENTITY)               mysql

@SequenceGenerator(name="teacherSEQ",sequenceName="teacherSEQ_DB")
public class Teacher { }

name="teacherSEQ"   这个name的指的是生成器的名字

sequenceName="teacherSEQ_DB" 表示数据库里面的名字

@GeneratedValue(strategy=GenerationType.SEQUENCE,generator="teacherSEQ")
    public int getId() {
        return id;
    }



//  经典留在这里    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>

        <!--   
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="connection.url">jdbc:mysql://localhost/hibernate</property>
        <property name="connection.username">root</property>
        <property name="connection.password">bjsxt</property>
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
    -->   
        <property name="connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
        <property name="connection.url">jdbc:oracle:thin:@localhost:1521:orcl</property>
        <property name="connection.username">scott</property>
        <property name="connection.password">tiger</property>
      	<property name="dialect">org.hibernate.dialect.OracleDialect</property>
     

        <!-- JDBC connection pool (use the built-in) -->
        <property name="connection.pool_size">1</property>

        

        <!-- Enable Hibernate's automatic session context management -->
        <property name="current_session_context_class">thread</property>

        <!-- Disable the second-level cache  -->
        <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>

        <!-- Echo all executed SQL to stdout -->
        <property name="show_sql">true</property>
        <property name="format_sql">true</property>

        <!-- Drop and re-create the database schema on startup -->
        <property name="hbm2ddl.auto">update</property>

        <mapping resource="com/demo/hibernate/Student.hbm.xml"/>
		<mapping class="com.demo.hibernate.Teacher"/>
    </session-factory>

</hibernate-configuration>


package com.demo.hibernate;

public class Student {

	private int id;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	private String name;
	private int age;

	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	
}


package com.demo.hibernate;
import java.util.Date;

import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import org.hibernate.annotations.GenericGenerator;


@Entity //实体类
@SequenceGenerator(name="teacherSEQ",sequenceName="teacherSEQ_DB")
public class Teacher {
	private int id;
	private String name;
	private String title;
	
	
	@Id
	@GeneratedValue(strategy=GenerationType.SEQUENCE,generator="teacherSEQ")
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = 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="com.demo.hibernate">
	<class name="Student">
		<id name="id">
			<generator class="native"></generator>
		</id>
		<property name="name"/>
		<property name="age"/>
	</class>
</hibernate-mapping>


package com.demo.hibernate;

import java.util.Date;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.cfg.Configuration;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

import com.demo.hibernate.Teacher;
import com.demo.hibernate.ZhiCheng;


public class HibernateIDTest {
	private static SessionFactory sf = null;
	@BeforeClass
	public static void beforClass() {  
			try {
				sf = new AnnotationConfiguration().configure().buildSessionFactory();
			} catch (Exception e) {
				e.printStackTrace();
			}
	}
	
	
	@Test
	public void testStudentSave() {
		Student s = new Student();
		s.setName("zhangsan");
		s.setAge(8);
		
		
		Session session = sf.getCurrentSession();
		session.beginTransaction();
		session.save(s);
		session.getTransaction().commit();
	}
	
	
	
	@Test
	public void testTeacherSave() {
		Teacher t = new Teacher();
		t.setName("t1");
		t.setTitle("ffff");
		
		
		Session session = sf.getCurrentSession();
		session.beginTransaction();
		session.save(t);
		session.getTransaction().commit();
	}
	

	@AfterClass
	public static void afterClass() {
		sf.close();
	}
	
	public static void main(String[] args) {
		beforClass();
	}
}


 表生成器,可以使数据库和数据跨平台

@javax.persistence.TableGenerator(
    name="EMP_GEN",
    table="GENERATOR_TABLE",
    pkColumnName = "key",
    valueColumnName = "hi"
    pkColumnValue="EMP",
    allocationSize=20
)




联合主键

1、实现序列号

2、重写equals和hashCode

package com.demo.hibernate;

public class StudentPK implements java.io.Serializable {
	private int id;
	private String name;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	@Override
	public boolean equals(Object o) {
		if(o instanceof StudentPK) {
			StudentPK pk = (StudentPK)o;
			if(this.id == pk.getId() && this.name.equals(pk.getName())) {
				return true;
			}
			
		}
		return false;
	}
	@Override
	public int hashCode() {  // 就是在相同哈希码中找对象进行equals 相同的就拿出来
		return this.name.hashCode();
	}
}



 

2、annotation方式

下面是定义组合主键的几种语法:

将组件类注解为@Embeddable,并将组件的属性注解为@Id

将组件的属性注解为@EmbeddedId

将类注解为@IdClass,并将该实体中所有属于主键的属性都注解为@Id

a) 将组件类注解为@Embeddable,并将组件的属性注解为@Id

组件类:

@Embeddable

public class TeacherPK implementsjava.io.Serializable{

    private int id;

    private String name;

    public int getId() {return id;  }

    public void setId(int id) {this.id = id;}

    public String getName() {   return name;}

    public void setName(Stringname) {  this.name = name;}

    @Override

    public boolean equals(Object o) {       ……}

    @Override

    public int hashCode() { return this.name.hashCode();    }

}

将组件类的属性注解为@Id,实体类中组件的引用

@Entity

public class Teacher {

  private TeacherPK pk;

  private String title;

 

  @Id

  public TeacherPK getPk(){

      return pk;

}}

 

b)  将组件的属性注解为@EmbeddedId

注意:只需要在实体类中表示复合主键属性前注解为@Entity,表示此主键是一个复合主键

       注意了,复合主键类不需要任何的注意。

@Entity

public class Teacher {

   private TeacherPK pk;

   private String title;  

 

   @EmbeddedId

   public TeacherPK getPk(){

       return pk;

   }}

c)  类注解为@IdClass,主键的属性都注解为@Id

需要将复合主键类建立好,不需要进行任何注解

在实体类中不需要进行复合主键类的引用

需要在实体类前面注解为@IdClass,并且指定一个value属性,值为复合主键类的class

需要在实体类中进行复合主键成员属性前面注解为@Id

如下:

@Entity

@IdClass(TeacherPK.class)

public class Teacher {

  //private TeacherPK pk;//不再需要

  private int id;

  private String name;   

  @Id

  public int getId() {return id;  }

  public void setId(int id) { this.id = id;   }

 

  @Id

  public String getName() {return name;}

  public void setName(Stringname) {this.name = name;

  }}

package com.demo.hibernate;

import javax.persistence.Embeddable;

// @Embeddable  //可以被嵌入的,就是说这个类的对象是另一个类的一部分 @Id
public class TeacherPK implements java.io.Serializable {
	private int id;
	private String name;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	@Override
	public boolean equals(Object o) {
		if(o instanceof TeacherPK) {
			TeacherPK pk = (TeacherPK)o;
			if(this.id == pk.getId() && this.name.equals(pk.getName())) {
				return true;
			}
			
		}
		return false;
	}
	@Override
	public int hashCode() {  // 就是在相同哈希码中找对象进行equals 相同的就拿出来
		return this.name.hashCode();
	}
}

package com.demo.hibernate;
import java.util.Date;

import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.SequenceGenerator;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import org.hibernate.annotations.GenericGenerator;


@Entity //实体类
@IdClass(TeacherPK.class)
public class Teacher {
	private TeacherPK pk;
	private int id;
	private String name;
	
	@Id
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	@Id
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	//	@Id
	/*@EmbeddedId
	public TeacherPK getPk() {
		return pk;
	}
	public void setPk(TeacherPK pk) {
		this.pk = pk;
	}*/
	private String title;
	
	
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
}


第14课 Hibernate核心开发接口(重点)

一、 Configuration(AnnotationConfiguration)

作用:进行配置信息的管理

目标:用来产生SessionFactory

可以在configure方法中指定hibernate配置文件,默认(不指定)时在classpath下加载hibernate.cfg.xml文件

加载默认的hibernate的配置文件

sessionFactory = newAnnotationConfiguration().configure().buildSessionFactory();

加载指定hibernate的配置文件

sessionFactory=newnnotationConfiguration().configure("hibernate.xml").buildSessionFactory();

只需要关注一个方法:buildSessionFactory();

二、 SessionFactory

作用:主要用于产生Session的工厂(数据库连接池)

当它产生一个Session时,会从数据库连接池取出一个连接,交给这个Session

Session session = sessionFactory.getCurrentSession();

         并且可以通过这个Session取出这个连接

         关注两个方法:

         getCurrentSession():表示当前环境没有Session时,则创建一个,否则不用创建

         openSession():     表示创建一个Session(3.0以后不常用),使用后需要关闭这个Session

         两方法的区别:

           ①、openSession永远是每次都打开一个新的Session,而getCurrentSession不是,是从上下文找、只有当前没有Session时,才创建一个新的Session

           ②、OpenSession需要手动close,getCurrentSession不需要手动close,事务提交自动close

           ③、getCurrentSession界定事务边界

上下文:

所指的上下文是指hibernate配置文件(hibernate.cfg.xml)中的“current_session_context_class”所指的值:(可取值:jta|thread|managed|custom.Class)

<property name="current_session_context_class">thread</property>

         常用的是:①、thread:是从上下文找、只有当前没有Session时,才创建一个新的Session,主要从数据界定事务

              ②、jta:主要从分布式界定事务,运行时需要Application Server来支持(Tomcat不支持)

             ③、managed:不常用

④、custom.Class:不常用

           

三、 Session

1、    管理一个数据库的任务单元

2、    save();

session.save(Object)

session的save方法是向数据库中保存一个对象,这个方法产生对象的三种状态

3、    delete() 

session.delete(Object)

   Object对象需要有ID

   对象删除后,对象状态为Transistent状态

4、    load()

格式: Session.load(Class arg0,Serializable arg1) throws HibernateException

    *arg0:需要加载对象的类,例如:User.class

    *arg1:查询条件(实现了序列化接口的对象):例"4028818a245fdd0301245fdd06380001"字符串已经实现了序列化接口。如果是数值类类型,则hibernate会自动使用包装类,例如 1

    * 此方法返回类型为Object,但返回的是代理对象。

    * 执行此方法时不会立即发出查询SQL语句。只有在使用对象时,它才发出查询SQL语句,加载对象。

    * 因为load方法实现了lazy(称为延迟加载、赖加载)

    * 延迟加载:只有真正使用这个对象的时候,才加载(才发出SQL语句)

    *hibernate延迟加载实现原理是代理方式。

    * 采用load()方法加载数据,如果数据库中没有相应的记录,则会抛出异常对象不找到(org.hibernate.ObjectNotFoundException)

    try {

        session =sf.openSession();

        session.beginTransaction();

       

         User user =(User)session.load(User.class,1);

           

        //只有在使用对象时,它才发出查询SQL语句,加载对象。

        System.out.println("user.name=" + user.getName());

           

        //因为此的user为persistent状态,所以数据库进行同步为龙哥。

        user.setName("发哥");

           

        session.getTransaction().commit();

    } catch (HibernateExceptione) {

        e.printStackTrace();

        session.getTransaction().rollback();

    } finally{

            if (session != null){

                if(session.isOpen()){

                    session.close();

                }

            }

    }

5、    Get()     

格式:Session.get(Class arg0,Serializable arg1)方法

* arg0:需要加载对象的类,例如:User.class

    * arg1:查询条件(实现了序列化接口的对象):

例"4028818a245fdd0301245fdd06380001"字符串已经实现了序列化接口。如果是基数类型,则hibernate会自动转换成包装类,如 1

    返回值: 此方法返回类型为Object,也就是对象,然后我们再强行转换为需要加载的对象就可以了。

            如果数据不存在,则返回null;

    注:执行此方法时立即发出查询SQL语句。加载User对象

加载数据库中存在的数据,代码如下:

try {

          session =sf.openSession();

          session.beginTransaction();

                 

           * 此方法返回类型为Object,也就是对象,然后我们再强行转换为需要加载的对象就可以了。

              如果数据不存在,则返回null

           * 执行此方法时立即发出查询SQL语句。加载User对象。

           */

          User user = (User)session.get(User.class, 1);

         

          //数据加载完后的状态为persistent状态。数据将与数据库同步。

          System.out.println("user.name=" + user.getName());

         

          //因为此的user为persistent状态,所以数据库进行同步为龙哥。

          user.setName("龙哥");

         

          session.getTransaction().commit();

      } catch(HibernateException e) {

          e.printStackTrace();

          session.getTransaction().rollback();

      } finally{

          if (session != null){

              if(session.isOpen()){

                  session.close();

              }

          }

6、    load()与get()区别

① 、 不存在对应记录时表现不一样;

② 、 load返回的是代理对象,等到真正使用对象的内容时才发出sql语句,这样就要求在第一次使用对象时,要求session处于open状态,否则出错

③ 、 get直接从数据库加载,不会延迟加载

get()和load()只根据主键查询,不能根据其它字段查询,如果想根据非主键查询,可以使用HQL

7、    update()

①        、用来更新detached对象,更新完成后转为为persistent状态(默认更新全部字段)

②        更新transient对象会报错(没有ID)

③        更新自己设定ID的transient对象可以(默认更新全部字段)

④        persistent状态的对象,只要设定字段不同的值,在session提交时,会自动更新(默认更新全部字段)

⑤        更新部分更新的字段(更改了哪个字段就更新哪个字段的内容)

a)       方法1:update/updatable属性

 xml:设定<property>标签的update属性,设置在更新时是否参数更新

<property name="name" update="false"/>

注意:update可取值为true(默认):参与更新;false:更新时不参与更新

annotateon:设定@Column的updatable属性值,true参与更新,false:不参与更新

    @Column(updatable=false)

    public String getTitle(){return title;}

注意:此种方法很少用,因为它不灵活

b)       方法二:dynamic-update属性

注意:此方法目前只适合xml方式,JAP1.0annotation没有对应的

在实体类的映射文件中的<class>标签中,使用dynamic-update属性,true:表示修改了哪个字段就更新哪个字段,其它字段不更新,但要求是同一个session(不能跨session),如果跨了session同样会更新所有的字段内容。

<class name="com.bjsxt.Student" dynamic-update="true">

          代码:

@Test

  public void testUpdate5() {    

      Sessionsession = sessionFactory.getCurrentSession();

      session.beginTransaction();

      Student s =(Student)session.get(Student.class, 1);

      s.setName("zhangsan5");

      //提交时,会只更新name字段,因为此时的s为persistent状态

      session.getTransaction().commit();

      s.setName("z4");

      Sessionsession2 = sessionFactory.getCurrentSession();

      session2.beginTransaction();

      //更新时,会更新所有的字段,因为此时的s不是persistent状态

      session2.update(s);

      session2.getTransaction().commit(); }

           如果需要跨session实现更新修改的部分字段,需要使用session.merget()方法,合并字段内容

@Test

  public void testUpdate6() {    

      Sessionsession = sessionFactory.getCurrentSession();

      session.beginTransaction();

      Student s =(Student)session.get(Student.class, 1);

      s.setName("zhangsan6");

      session.getTransaction().commit();

      s.setName("z4");

      Sessionsession2 = sessionFactory.getCurrentSession();

      session2.beginTransaction();

      session2.merge(s);

      session2.getTransaction().commit()}

这样虽然可以实现部分字段更新,但这样会多出一条select语句,因为在字段数据合并时,需要比较字段内容是否已变化,就需要从数据库中取出这条记录进行比较

c)      使用HQL(EJBQL)面向对象的查询语言(建议)

  @Test

  public void testUpdate7() {    

      Sessionsession = sessionFactory.getCurrentSession();

      session.beginTransaction();

      Query q =session.createQuery(

"update Student s sets.name='z5' where s.id = 1");

      q.executeUpdate();

      session.getTransaction().commit();     

  }  

8、    saveOrUpdate()

在执行的时候hibernate会检查,如果对象在数据库中已经有对应的记录(是指主键),则会更新update,否则会添加数据save

9、    clear()

清除session缓存

无论是load还是get,都会首先查找缓存(一级缓存,也叫session级缓存),如果没有,才会去数据库查找,调用clear()方法可以强制清除session缓存

    Session session= sessionFactory.getCurrentSession();

    session.beginTransaction();

    Teacher t =(Teacher)session.load(Teacher.class, 1);

    System.out.println(t.getName());       

    session.clear();       

    Teacher t2 =(Teacher)session.load(Teacher.class, 1);

    System.out.println(t2.getName());

    session.getTransaction().commit();

注意:这样就会发出两条SELECT语句,如果把session.clear()去除,则只会发出一条SELECT语句,因为第二次load时,是使用session缓存中ID为1的对象,而这个对象已经在第一次load到缓存中 了。

10、 flush()

在hibernate中也存在flush这个功能,在默认的情况下session.commit()之前时,其实执行了一个flush命令。

Session.flush功能:

n         清理缓存;

n         执行sql(确定是执行SQL语句(确定生成update、insert、delete语句等),然后执行SQL语句。)

 

Session在什么情况下执行flush:

①          默认在事务提交时执行;

注意:flush时,可以自己设定,使用session.setFlushMode(FlushMode)来指定。

  session.setFlushMode(FlushMode);

FlushMode的枚举值:

l     FlushMode.ALWAYS:任务一条SQL语句,都会flush一次

l     FlushMode.AUTO  :自动flush(默认)

l     FlushMode.COMMIT: 只有在commit时才flush

l     FlushMode.MANUAL:手动flush。

l    FlushMode.NEVER :永远不flush  此选项在性能优化时可能用,比如session取数据为只读时用,这样就  

不需要与数据库同步了

        注意:设置flush模式时,需要在session开启事务之前设置。

②         可以显示的调用flush;

③         在执行查询前,如:iterate.

注:如果主键生成策略是uuid等不是由数据库生成的,则session.save()时并不会发出SQL语句,只有flush时才会发出SQL语句,但如果主键生成策略是native由数据库生成的,则session.save的同时就发出SQL语句。

 

11、 evict()

例如:session.evict(user)

作用:从session缓存(EntityEntries属性)中逐出该对象

但是与commit同时使用,会抛出异常

session = HibernateUtils.getSession();

tx = session.beginTransaction();

   

User1 user = new User1();

user.setName("李四");

user.setPassword("123");

user.setCreateTime(new Date());

user.setExpireTime(new Date());

           

//利用Hibernate将实体类对象保存到数据库中,因为user主键生成策略采用的是uuid,所以调用完成save后,只是将user纳入session的管理,不会发出insert语句,但是id已经生成,session中的existsInDatabase状态为false

session.save(user);

               

session.evict(user);//从session缓存(EntityEntries属性)中逐出该对象

//无法成功提交,因为hibernate在清理缓存时,在session的临时集合(insertions)中取出user对象进行insert操作后需要更新entityEntries属性中的existsInDatabase为true,而我们采用evict已经将user从session中逐出了,所以找不到相关数据,无法更新,抛出异常。

           

tx.commit();

 

解决在逐出session缓存中的对象不抛出异常的方法:

在session.evict()之前进行显示的调用session.flush()方法就可以了。

session.save(user);

               

//flush后hibernate会清理缓存,会将user对象保存到数据库中,将session中的insertions中的user对象清除,并且会设置session中的existsInDatabase状态为false

session.flush();

           

session.evict(user);//从session缓存(EntityEntries属性)中逐出该对象

           

//可以成功提交,因为hibernate在清理缓存时,在Session的insertions中集合中无法找到user对象所以不会发出insert语句,也不会更新session中existsInDatabase的状态。

tx.commit();

 

hibernate.current_session_context_class   jta |thread          (<property name="current_session_context_class">thread</property>)

jta 是针对于分布式,即多个数据库

thread 是针对于一个数据库




第15课 持久化对象的三种状态

一、 瞬时对象(Transient Object):

使用new操作符初始化的对象不是立刻就持久的。它们的状态是瞬时的,也就是说它们没有任何跟数据库表相关联的行为,只要应用不再引用这些对象(不再被任何其它对象所引用),它们的状态将会丢失,并由垃圾回收机制回收

二、 持久化对象(Persistent Object):

持久实例是任何具有数据库标识的实例,它有持久化管理器Session统一管理,持久实例是在事务中进行操作的----它们的状态在事务结束时同数据库进行同步。当事务提交时,通过执行SQL的INSERT、UPDATE和DELETE语句把内存中的状态同步到数据库中。

三、 离线对象(Detached Object):

Session关闭之后,持久化对象就变为离线对象。离线表示这个对象不能再与数据库保持同步,它们不再受hibernate管理。

 

四、 三种状态的区分:

1、  有没有ID,(如果没有则是Transient状态)

2、  ID在数据库中有没有

3、  在内存里有没有(session缓存)

五、 总结:

Transient对象:随时可能被垃圾回收器回收(在数据库中没有于之对应的记录,应为是new初始化),而执行save()方法后,就变为Persistent对象(持久性对象),没有纳入session的管理

                            内存中一个对象,没有ID,缓存中也没有

Persistent对象:在数据库有存在的对应的记录,纳入session管理。在清理缓存(脏数据检查)的时候,会和数据库同步。

                            内存中有、缓存中有、数据库有(ID)

Detached对象:也可能被垃圾回收器回收掉(数据库中存在对应的记录,只是没有任何对象引用它是指session引用),注引状态经过Persistent状态,没有纳入session的管理

内存有、缓存没有、数据库有(ID)

————————————————————————————


    @Column(updatable=false)  // 不要让此字段更新
    public String getYouWifeName() {
        return youWifeName;
    }


   <class name="com.demo.hibernate.Student" dynamic-update="true">      动态更新,在数据库里面只更新你要设置的,其他的不执行,提高效率。 Annotation 没有,因此使用的时候用xml


@Test
	public void testUpload5() {
		Session session = sf.getCurrentSession();  
		session.beginTransaction();
		Student s = (Student)session.get(Student.class, 1);
		s.setName("tianshan"); 
		session.getTransaction().commit();
	}


session常用的方法

package com.demo.hibernate;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

import com.demo.hibernate.Teacher;
import com.demo.hibernate.Student;

public class HibernateCoreAPITest {
	private static SessionFactory sf = null;
	@BeforeClass
	public static void beforClass() {  
			try {
				sf = new AnnotationConfiguration().configure().buildSessionFactory();
			} catch (Exception e) {
				e.printStackTrace();  
			}
	}
	
	
	@Test
	public void testStudentSave() {
		
		Student s = new Student();
		s.setId(2);
		s.setName("ff");
		s.setAge(8);
		
//		 Session session1 = sf.openSession();  //用于是创建新的session  
		Session session = sf.getCurrentSession();  //如果原来的session 没有关闭 用原来的
		session.beginTransaction();
		session.save(s);
		session.getTransaction().commit();
	}
	
	/* 以下是Session里面常用方法
	 * 1、session 里面有一个缓存
	 * 2、拿出来的对象有三个状态
	 * 3、缓存与数据库之间同步 
	 */
	
	@Test
	public void testSaveWith3State() {
		Teacher t = new Teacher();
		t.setName("ggg");
		t.setTitle("hhh");
		t.setYouWifeName("uuu");
		
		
		Session session = sf.getCurrentSession();
		session.beginTransaction();
		session.save(t);
		System.out.println(t.getId());
		session.getTransaction().commit();
		System.out.println(t.getId());
	}
	

	@Test
	public void testDelete() {
		Teacher t = new Teacher();
		t.setName("mmm");
		t.setTitle("ffff");
		t.setYouWifeName("hhh");
		
		
		Session session = sf.getCurrentSession();
		session.beginTransaction();
		session.save(t);
		System.out.println(t.getId());
		session.getTransaction().commit();
		
		Session session2 = sf.getCurrentSession();
		session2.beginTransaction();
		session2.delete(t);
		
		session2.getTransaction().commit();
	}
	
	@Test
	public void testDelete2() {
		Teacher t = new Teacher();
		t.setId(2);
		
		Session session = sf.getCurrentSession();
		session.beginTransaction();
		session.delete(t);
		session.beginTransaction().commit();
		
	}
	

	@Test
	public void testLoad() {
		Session session = sf.getCurrentSession();
		session.beginTransaction();
		Teacher t = (Teacher)session.load(Teacher.class, 1);
		
		session.beginTransaction().commit();
		System.out.println(t.getClass()); //证明是否是代理对象
//		System.out.println(t.getName());
		
	}
	
	@Test
	public void testGet() {
		Session session = sf.getCurrentSession();
		session.beginTransaction();
		Teacher t = (Teacher)session.get(Teacher.class, 1);
	
		session.beginTransaction().commit();
		System.out.println(t.getClass()); //证明是否是代理对象
//		System.out.println(t.getName());
	}
	

	@Test
	public void testUpdate1() {
		// Detached ---->  Persistent
		Session session = sf.getCurrentSession();
		session.beginTransaction();
		Teacher t = (Teacher)session.get(Teacher.class, 1);
		session.beginTransaction().commit();
		
		t.setName("zhongguo");
		
		Session session2 = sf.getCurrentSession();
		session2.beginTransaction();
		session2.update(t);
		session2.beginTransaction().commit();
		//Persistent
	}
	
	@Test
	public void testUpdate2() {
		// Transient  --->  Persistent  不行 因为没有ID
		Teacher t = new Teacher();
		t.setName("zhongguo");
		
		Session session2 = sf.getCurrentSession();
		session2.beginTransaction();
		session2.update(t);
		session2.beginTransaction().commit();
		//Persistent
	}
	
	@Test
	public void testUpdate3() {
		// Transient  --->  Persistent  不行 因为没有ID
		Teacher t = new Teacher();
		t.setId(1);     //手动设置ID 可以 前提是数据库里面有对应的记录
		t.setName("zhongguo");
		
		Session session2 = sf.getCurrentSession();
		session2.beginTransaction();
		session2.update(t);
		session2.beginTransaction().commit();
		//Persistent
	}
	
	

	@Test
	public void testUpdate4() {
		Session session2 = sf.getCurrentSession();
		session2.beginTransaction();
		Teacher t = (Teacher)session2.get(Teacher.class, 1);
		t.setName("mein");
		session2.beginTransaction().commit();
	}
	
	
	@Test
	public void testUpload5() {
		Session session = sf.getCurrentSession();  
		session.beginTransaction();
		Student s = (Student)session.get(Student.class, 1);
		s.setName("tianshan"); 
		session.getTransaction().commit();
	}
	
	@Test
	public void testUpload6() {
		Session session = sf.getCurrentSession();  
		session.beginTransaction();
		Student s = (Student)session.get(Student.class, 1);
		s.setName("wangsan"); 
		session.getTransaction().commit();
		
		s.setName("huangshan");
		
		//上面是Detached,下面新开启Session,因此跟上面没比较,所以全部更新  
		Session session1 = sf.getCurrentSession();  
		session1.beginTransaction();
		session1.update(s);
		session1.getTransaction().commit();
	}
	
	

	@Test
	public void testUpload7() {
		Session session = sf.getCurrentSession();  
		session.beginTransaction();
		Student s = (Student)session.get(Student.class, 1);
		s.setName("wangsan"); 
		session.getTransaction().commit();
		
		s.setName("huangshan");
		
		//上面是Detached,下面新开启Session,因此跟上面没比较,所以全部更新  
		Session session1 = sf.getCurrentSession();  
		session1.beginTransaction();
		session1.merge(s);   // 合并,只更新改过的
		session1.getTransaction().commit();
		
		
	}
	
	@Test
	public void testUpload8() {
		Session session = sf.getCurrentSession();  
		session.beginTransaction();
		Query q = session.createQuery("update Student s set s.name='m2' where s.id = 1");
		q.executeUpdate();
		session.getTransaction().commit();
	}
	

	@Test
	public void testSaveOrUpload9() {
		Teacher t = new Teacher();
		t.setName("t4");
		t.setTitle("ffff");
		t.setYouWifeName("hhh");
		
		
		Session session = sf.getCurrentSession();
		session.beginTransaction();
		session.saveOrUpdate(t);
		session.getTransaction().commit();

		t.setName("t5");
		Session session2 = sf.getCurrentSession();
		session2.beginTransaction();
		session2.saveOrUpdate(t);
		session2.getTransaction().commit();
	
	}
	@Test
	public void testClear() {
		Session session = sf.getCurrentSession();  
		session.beginTransaction();
		Student s = (Student)session.get(Student.class, 1);
		System.out.println(s.getName());
		
		session.clear();  //跟缓存打交道
		
		Student s1 = (Student)session.get(Student.class, 1);
		System.out.println(s1.getName());
		session.getTransaction().commit();
	}
	
	
	@Test
	public void testFlush() {
		Session session = sf.getCurrentSession();  
		session.beginTransaction();
		Student s = (Student)session.get(Student.class, 1);
		s.setName("kk");
		session.flush();  //跟数据库打交道
		s.setName("kkkk");
		session.getTransaction().commit();
	}
	
	@Test
    public void testSchemaExport() {  //生成建表语句
        new SchemaExport(new AnnotationConfiguration().configure()).create(false, true);
    }
    

	
	@AfterClass
	public static void afterClass() {
		sf.close();
	}
	
	public static void main(String[] args) {
		beforClass();
	}
}




http://blog.csdn.net/tanyit/article/details/6987600

共有 人打赏支持
粉丝 4
博文 11
码字总数 42451
×
frankbak
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: