hibernate之helloworld
一、helloworld
添加hibernate的依赖和数据库连接的依赖
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.2.4.Final</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.44</version>
</dependency>
在 resource 目录下创建 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.username">root</property>
<property name="connection.password">root</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql:///hibernate</property>
<!-- hibernate 所使用的数据库方言 -->
<property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
<!-- 执行操作时是否在控制台打印 SQL -->
<property name="show_sql">true</property>
<!-- 表生成策略 -->
<property name="hbm2ddl.auto">update</property>
<!-- 指定关联的 .hbm.xml 文件 -->
<mapping resource="News.hbm.xml" />
</session-factory>
</hibernate-configuration>
数据库方言:
数据库类型 Hibernate sql方言
DB2 org.hibernate.dialect.DB2Dialect
DB2 AS/400 org.hibernate.dialect.DB2400Dialect
DB2 OS390 org.hibernate.dialect.DB2390Dialect
PostgreSQL 8.1 org.hibernate.dialect.PostgreSQL81Dialect
PostgreSQL 8.2 and later org.hibernate.dialect.PostgreSQL82Dialect
MySQL5 org.hibernate.dialect.MySQL5Dialect
MySQL5 with InnoDB org.hibernate.dialect.MySQL5InnoDBDialect
MySQL with MyISAM org.hibernate.dialect.MySQLMyISAMDialect
Oracle (any version) org.hibernate.dialect.OracleDialect
Oracle 9i org.hibernate.dialect.Oracle9iDialect
Oracle 10g org.hibernate.dialect.Oracle10gDialect
Oracle 11g org.hibernate.dialect.Oracle10gDialect
Sybase ASE 15.5 org.hibernate.dialect.SybaseASE15Dialect
Sybase ASE 15.7 org.hibernate.dialect.SybaseASE157Dialect
Sybase Anywhere org.hibernate.dialect.SybaseAnywhereDialect
Microsoft SQL Server 2000 org.hibernate.dialect.SQLServerDialect
Microsoft SQL Server 2005 org.hibernate.dialect.SQLServer2005Dialect
Microsoft SQL Server 2008 org.hibernate.dialect.SQLServer2008Dialect
SAP DB org.hibernate.dialect.SAPDBDialect
Informix org.hibernate.dialect.InformixDialect
HypersonicSQL org.hibernate.dialect.HSQLDialect
H2 Database org.hibernate.dialect.H2Dialect
Ingres org.hibernate.dialect.IngresDialect
Progress org.hibernate.dialect.ProgressDialect
Mckoi SQL org.hibernate.dialect.MckoiDialect
Interbase org.hibernate.dialect.InterbaseDialect
Pointbase org.hibernate.dialect.PointbaseDialect
FrontBase org.hibernate.dialect.FrontbaseDialect
Firebird org.hibernate.dialect.FirebirdDialect
实体
public class News {
private Integer id;
private String title;
private String content;
......
}
创建 News.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.hw.entity">
<class name="News" table="NEWS" dynamic-insert="true">
<!--dynamic-insert="true" 时表示插入对象时空的字段不插入 -->
<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="native" />
<!-- 指定主键的生成策略, native: 使用数据库本地方式 -->
</id>
<property name="title" not-null="true"
length="50" type="java.lang.String" column="TITLE">
</property>
<property name="content">
<column name="CONTENT" sql-type="text"></column>
<!--数据库改字段的名字和类型-->
</property>
</class>
</hibernate-mapping>
执行会自动创表,插入数据
// 1.创建SessionFactory
Configuration configuration=new Configuration().configure();
SessionFactory sessionFactory=configuration.buildSessionFactory();
// 2. 获得一个 Session 对象
Session session = sessionFactory.openSession();
// 3. 开启事务
Transaction transaction = session.beginTransaction();
// 4. 执行保存操作
News news = new News("标题","正文");
session.save(news);
// 5. 提交事务
transaction.commit();
// 6. 关闭 Session
session.close();
// 7. 关闭 SessionFactory 对象
sessionFactory.close();
System.out.println(news);
主键生成策略
increment:代理主键,适合于所有数据库,由hibernate维护主键自增,和底层数据库无关,但是不适合于2个或以上hibernate进程。
identity:代理主键,适合于Mysql或ms sql server等支持自增的dbms,主键值不由hibernate维护。
sequence:代理主键,适合于oracle等支持序列的dbms,主键值不由hibernate维护,由序列产生。
native:代理主键,根据底层数据库的具体特性选择适合的主键生成策略,如果是mysql或sqlserver,选择identity,如果是oracle,选择sequence。
hilo:代理主键,hibernate把特定表的字段作为hign值,生成主键值
uuid.hex:代理主键,hibernate采用uuid 128位算法生成基于字符串的主键值
assigned:适合于由java指定主键,一般使用uuid,保存对象时如果主键为空会抛异常。
表生成策略
–create : 会根据 .hbm.xml 文件来生成数据表,但是每次运行都会删除上一次的表,重新生成表,哪怕二次没有任何改变
–create-drop : 会根据.hbm.xml文件生成表,但是SessionFactory一关闭,表就自动删除
–update : 最常用的属性值,也会根据.hbm.xml文件生成表,但若.hbm.xml 文件和数据库中对应的数据表的表结构不同,Hiberante 将更新数据表结构,但不会删除已有的行和列
–validate : 会和数据库中的表进行比较,若.hbm.xml文件中的列在数据表中不存在,则抛出异常
数据库字段类型
hibernate的映射关系如下:
Hibernate 映射类型 java 类型 标准 sql 类型
integer int or Integer INTEGER
long long or java.lang.Long BIGINT
short short or java.lang.Short SMALLINT
float float or java.lang.Float FLOAT
double double or java.lang.Double DOUBLE
big_decimal java.math.BigDecimal NUMERIC
character java.lang.String CHAR(1)
string java.lang.String VARCHAR
byte byte or java.lang.Byte TINYINT
boolean boolean or java.lang.Boolean BIT
yes_no boolean or java.lang.Boolean CHAR(1)('Y' or 'N')
true_false boolean or java.lang.Boolean CHAR(1)('Y' or 'N')
date java.util.Date or java.sql.Date DATE
time java.util.Date or java.sql.Time TIME
timestamp java.util.Date or java.sql.TimeStamp TIMESTAMP
calendar java.util.Calendar TIMESTAMP
calendar_date java.util.Calendar DATE
binary byte[] VARBINARY( or BLOB)
text java.lang.String CLOB
serializable java.io.Serializable VARBINARY (or BLOB)
clob java.sql.Clob CLOB
blob java.sql.Blob BLOB
class java.lang.Class VARCHAR
locale java.util.Locale VARCHAR
timezone java.util.TimeZone VARCHAR
currency java.util.Currency VARCHAR
二、Session 概述
为了方便我们使用junit的测试前后注解
private SessionFactory sessionFactory;
private Session session;
private Transaction transaction;
@Before
public void init() {
Configuration configuration=new Configuration().configure();
sessionFactory=configuration.buildSessionFactory();
session = sessionFactory.openSession();
transaction = session.beginTransaction();
}
@After
public void destroy() {
transaction.commit();
session.close();
sessionFactory.close();
}
Session 接口是Hibernate向应用程序提供的操纵数据库的最主要的接口,它提供了基本的保存,更新,删除和加载Java 对象的方法.
Session 具有一个缓存(一级缓存), 位于缓存中的对象称为持久化对象, 它和数据库中的相关记录对应. Session 能够在某些时间点, 按照缓存中对象的变化来执行相关的 SQL 语句, 来同步更新数据库, 这一过程被称为刷新缓存(flush)
站在持久化的角度, Hibernate 把对象分为 4 种状态:
1.持久化状态
2.临时状态
3.游离状态
4.删除状态
Session 的特定方法能使对象从一个状态转换到另一个状态.
一级缓存(基于session的缓存)
一级缓存hibernate默认开启
一级缓存表示session不关闭的情况下,该session保存的对象多次查询从缓存中获取
News news = (News) session.get(News.class, 1);
System.out.println(news);
News news2 = (News) session.get(News.class, 1);
System.out.println(news2);
如上:当第二次查询时不在去数据库里面查询,而是从session里面获取,共发一次sql
除非中间刷新缓存session.flush();关闭session 和session.clear();
session.refresh(news);与session.flush();的区别
refresh 强制从数据库查询该对象 ,获取数据库最新纪录后设置对象的属性
flush 强制将修改过后的对象刷新到数据库,并清除一级缓存
对象的四个状态
临时状态(Transient): 在使用代理主键的情况下, OID 通常为 null 不处于 Session 的缓存中 在数据库中没有对应的记录
持久化状态 (也叫”托管”)(Persist): OID 不为 null 位于 Session 缓存中 若在数据库中已经有和其对应的记录, 持久化对象和数据库中的相关记录对应 Session 在 flush 缓存时, 会根据持久化对象的属性变化, 来同步更新数据库 在同一个 Session 实例的缓存中, 数据库表中的每条记录只对应唯一的持久化对象
删除状态(Removed) 在数据库中没有和其 OID 对应的记录 不再处于 Session 缓存中 一般情况下, 应用程序不该再使用被删除的对象
游离状态(也叫”脱管”) (Detached): OID 不为 null 不再处于 Session 缓存中 一般情况需下, 游离对象是由持久化对象转变过来的, 因此在数据库中可能还存在与它对应的记录
三、对象的基本操作
持久化(保存)
News news = new News("Java", "SUN", new Date());
session.save(news);
Session 的 save() 方法使一个临时对象转变为持久化对象
把对象加入到 Session 缓存中, 使它进入持久化状态 选用映射文件指定的标识符生成器, 为持久化对象分配唯一的 OID. 计划执行一条 insert 语句
在 flush 缓存的时候 Hibernate 通过持久化对象的 OID 来维持它和数据库相关记录的对应关系.
当 News 对象处于持久化状态时, 不允许程序随意修改它的 ID
persist() 和 save() 区别:
当对一个 OID 不为 Null 的对象执行 save() 方法时, 会把该对象以一个新的 OID 保存到数据库中; 但执行 persist() 方法时会抛出一个异常.
对象查询(单个)
News news = (News) session.get(News.class, 1);
News news = (News) session.load(News.class, 1);
get 与 load:
-
执行 get 方法: 会立即加载对象. 执行 load 方法, 若不适用该对象, 则不会立即执行查询操作, 而返回一个代理对象,get 是 立即检索, load 是延迟检索.
-
load 方法可能会抛出 LazyInitializationException 异常: 在需要初始化 代理对象之前已经关闭了 Session
-
若数据表中没有对应的记录, Session 也没有被关闭. get 返回 null load 若不使用该对象的任何属性, 没问题; 若需要初始化了,抛出异常.
延迟加载指的就是,当完成load操作之后,并不会马上发出sql语句,只有在使用到该对象时才会发出sql 当完成load之后,u其实是一个代理对象,这个代理对象中仅仅只有一个id的值
修改单个对象
News news = (News) session.get(News.class, 1);
news.setAuthor("SUN");
session.update(news);
update:
-
若更新一个持久化对象, 不需要显示的调用 update 方法. 因为在调用 Transaction 的 commit() 方法时, 会先执行 session 的 flush 方法. (如上面的第三句没有必要)
-
更新一个游离对象, 需要显式的调用 session 的 update 方法. 可以把一个游离对象 变为持久化对象 需要注意的:
-
无论要更新的游离对象和数据表的记录是否一致, 都会发送 UPDATE 语句. 如何能让 updat 方法不再盲目的出发 update 语句呢 ? 在 .hbm.xml 文件的 class 节点设置 select-before-update=true (默认为 false). 但通常不需要设置该属性.
-
若数据表中没有对应的记录, 但还调用了 update 方法, 会抛出异常
-
当 update() 方法关联一个游离对象时, 如果在 Session 的缓存中已经存在相同 OID 的持久化对象, 会抛出异常. 因为在 Session 缓存中 不能有两个 OID 相同的对象!
Session 的saveOrUpdate()方法同时包含了 save() 与 update() 方法的功能。id为空时save ,不为空时update
删除对象
News news = (News) session.get(News.class, 163840);
session.delete(news);
delete: 执行删除操作.
只要 OID 和数据表中一条记录对应, 就会准备执行 delete 操作 若 OID 在数据表中没有对应的记录, 则抛出异常
可以通过设置 hibernate 配置文件 hibernate.use_identifier_rollback 为 true, 使删除对象后, 把其 OID 置为 null
舍弃修改
News news1 = (News) session.get(News.class, 1);
News news2 = (News) session.get(News.class, 2);
news1.setTitle("AA");
news2.setTitle("BB");
session.evict(news1);
evict: 从 session 缓存中把指定的持久化对象移除 * 使news1的修改不影响数据库