hibernate复习第(一)天
首先导入jar。
这个版本是3.2.5
开发流程:
1、由Domain object ->mapping ->db (官方推荐)
2、由DB开始,使用工具生成mapping和Domain object。(常用)
3、由映射文件开始
hibernate的bean的要求:
1、有一个缺省的构造,也就是无参构造
2、有一个id属性,对应数据库的主键。(可选)
3、非final的类。对懒加载影响(可选)
mapping映射文件。模板可以从hibernate下载文件的eq文件夹下的子文件夹中找到:
<?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="cn.itcast.hibernate.domain"> <class name="User"> <id name="id" > <generator class="native"/> </id> <property name="name"/> <property name="birthday"/> </class> </hibernate-mapping>
class,对应java类,name对应类名,和package的属性组合得到类的地址
<class name="User" table="user">可以有一个table属性,对应数据库表名,不写表示默认与类名相同
<id name="id" column="id">可以有一个column属性,对应数据表中的列名,不写默认与类名相同
<generator >表示以何种方式生成主键
<property name="name" column="">属性,name对应java类的字段,column对应数据表的列名,也是可省略。如果对应的列名是唯一的的话,可以在<property 中加上unique="true"/>
注意:这里的hibernate映射文件就是用于说明java对象与哪个表中的记录相对应,以及java对象中的各个属性分别对应表中的哪一项,不同性质的属性(例如,主键和普通属性)用不同的标签来映射,如果java对象中的某个属性不需要存储在数据库中,那么在hibernate映射文件中就不需要配置这个属性。
两个问题:
关于使用表名和字段与关键字冲突的问题。
如果表名和字段与关键字啊发生冲突,解决方案有两种:
使用column和table,改表名或字段名;
如果表名或者字段名不允许更改,可以在table或者column中字段前面加上符号"`",例如:<class name="User" column="`user`">.这个符号是键盘中~对应的那个键在英文状态下的符号
hibernate.cfg.xml配置文件记不住怎么办?
这个我们一般不记,在hibernate文件夹下的etc文件夹下有一个hibernate.properties文件夹,这里所有的配置信息都可以在这里查找得到
hibernate.cfg.xml文件:模板在 etc文件夹下面可以找到:
<!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="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/demo</property> <property name="hibernate.connection.username">guodaxia</property> <property name="hibernate.connection.password">961012gz</property> <property name="hibernate.hbm2ddl.auto">create</property> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <property name="show_sql">true</property> <mapping resource="cn/itcast/hibernate/domain/User.hbm.xml"/> </session-factory> </hibernate-configuration>
注意:
url中直接写jdbc:mysql:///demo表示地址是本机,端口是默认端口3306
5个必填属性:
url、驱动、用户名、密码、方言(方言主要是各个数据库分页语句不一样)
hibernate.hbm2ddl.auto属性:
4个可选值:
create-drop(创建和删除,启动时创建,使用后删除,一般在测试使用)
create(创建,启动时创建,使用后不删除,再次启动前删除后再创建,一般测试使用)
update(更新)
validate(检验映射文件与表是否对应,如果不对应报错不执行更新操作)
show_sql属性:是否显示执行的sql语句
<mapping resource=""/>映射文件的路径
hibernate如何操作数据库。
/* * hibernate初始化的过程,这个过程一般只做一次 * 所以我们一般做一个工具类 */ Configuration cfg=new Configuration(); cfg.configure(); SessionFactory sf=cfg.buildSessionFactory(); Session s=sf.openSession();
首先得到Configuration对象,使用该构造hibernate会自动加载classpath下面的hibernate.properties文件;
cfg.configuration();如果存在的话,hibernate自动加载classpath下的hibernate.cfg.xml配置文件。当然也可以加参数表示映射文件的文件路径和文件名,所以如果即写了hibernate.properties又写了hibernate.cfg.xml如果有相同属性配置,后者会覆盖前者。
创建sessionFactory工厂,这个类似于JDBC的DriverManager;
通过工厂创建session,session相当于JDBC中的Connection。
说明:
既然取读的是classpath下面的内容,为什么我们的配置文件都是放在src下面呢?这是因为myeclipes编译的时候会自动将src目录下的文件编译到classpath中去。
操作数据表:使用Session接口。
因为hibernate文件初始化比较耗费资源,我们一般书写一个工具类帮助处理:
package cn.itcast.hibernate; import java.io.Serializable; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; public final class HibernateUtil { /* * 设计成为单例,或者将所有的放射设计成为静态的 */ private static SessionFactory sessionFactory; private static ThreadLocal<Session> sessionThread;/* 使用threadLocal优化连接 */ private HibernateUtil(){ } static{ Configuration cfg=new Configuration(); cfg.configure();//从classPath里面读取配置文件。如果名字不是hibernate.cfg.xml的话需要特定指出,src下的文件会自动编译到classPath中 sessionFactory=cfg.buildSessionFactory(); sessionThread=new ThreadLocal<Session>(); } public static SessionFactory getSessionFactory(){ return sessionFactory; } public static Session getSession(){ Session s=sessionThread.get(); if(s==null){ s=sessionFactory.openSession(); }else{ sessionThread.set(s); } return s; } }
java对象的几种状态:
对象状态
瞬时(transient):数据库中没有数据与之对应,超过作用域会被JVM垃圾回收器回收,一般是new出来的与session没有关联的对象
持久(persistent):数据库中有数据与之对应,当前与session有关联,并且相关联的session没有关闭,事务没有提交,持久对象状态发生改变,在事务提交时会影响到数据库(hibernate能检测到);
持久化状态的时候如果你修改了该对象会自动调用update方法。
脱管:数据库中有数据与之对应,当前session与之无关联。save等操作后的java类或者查询得到的java类都是这种状态。托管状态的对象修改后只能是自己调用update方法才能对数据库进行修改。
Session对象的一些常见方法:
Transaction beginTransaction();开启事务
get(Class,Serializable)根据主键获取一条数据
load(Class,Serializable)根据主键获取一条数据.具有懒加载特性。懒加载类似new一封User子类
save(Object).保存一条数据
persist(Object).保存一条数据。
save和persist的区别是:在没有开启事务的情况下,save方法会先插入数据再回滚,而persist方法不会插入记录也就不需要回滚
update(Object):将对象更新到数据库
saveOrUpdate(Object):hibernate自动检测对象是瞬时状态还是脱管状态,然后执行insert或者update语句
merge(Object):和saveOrUpdate类似,区别在saveOrUpdate方法操作之后会改变对象的状态,变成持久状态,而merge之后还是脱管状态
Session s=HibernateUtil.getSession(); User user=new User(); user.setName("zhangSan"); user.setBirthday(new Date()); s.save(user); s.close();
上面的代码执行完之后,sql语句正常但是数据库中却没有任何记录。这是因为:
JDBC是自动提交的,但是hibernate的缺省将这个功能关闭,必须自己开启使用事务才会生效。事务的创建方式:
Transaction tx=session.beginTransaction();
如果不需要开启提交事务提交事务就可以操作数据库数据的话,注意一下你的表结构,看你的引擎
标准的操作数据库的结构:
static void addUser(User user){//比较规范的hibernate的一个写法 Session s=null; Transaction tx=null; try{ s=HibernateUtil.getSession();; tx=s.beginTransaction(); s.save(user); user.setName("new name");//这个user是持久状态 user.setBirthday(new Date()); tx.commit(); }catch(HibernateException e){ if(tx!=null) tx.rollback(); throw e; }finally{ if(s!=null) s.close(); } }
操作数据库的结构也可以写成这个样子:
static void addUser1(User user){//可以简写成为这个样子,因为hibernate接到异常会自动向外抛,如果数据库没有得到事务提交信号请求会自动回滚 Session s=null; Transaction tx=null; try{ s=HibernateUtil.getSession();; tx=s.beginTransaction(); s.save(user); tx.commit(); }finally{ if(s!=null) s.close(); } }
基本操作的一些代码:
package cn.itcast.hibernate; import java.util.Date; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.Transaction; import org.junit.Test; import cn.itcast.hibernate.domain.User; public class Base { public static void main(String[] args) { /* * hibernate初始化的过程,这个过程一般只做一次 * 所以我们一般做一个工具类 */ // Configuration cfg=new Configuration(); // cfg.configure(); // SessionFactory sf=cfg.buildSessionFactory(); // Session s=sf.openSession(); Session s=HibernateUtil.getSession(); //JDBC是自动提交的,但是hibernate的缺省将这个功能关闭,必须自己开启使用事务才会生效 //如果必须要开启提交事务就可以操作数据库数据的话,注意一下你的表结构,看你的引擎 User user=new User(); user.setName("zhangSan"); user.setBirthday(new Date()); // Transaction tx=s.beginTransaction(); // s.save(user); // tx.commit(); // s.close(); // System.out.println("end"); addUser(user); System.out.println("id:"+user.getId()); // User u=getUser(user.getId()); User u=(User) s.load(User.class, user.getId()); System.out.println("name:"+u.getName()); } static void addUser(User user){//比较规范的hibernate的一个写法 Session s=null; Transaction tx=null; try{ s=HibernateUtil.getSession();; tx=s.beginTransaction(); s.save(user); // s.persist(user); user.setName("new name");//这个user是持久状态 user.setBirthday(new Date()); tx.commit(); }catch(HibernateException e){ if(tx!=null) tx.rollback(); throw e; }finally{ if(s!=null) s.close(); } } static void addUser1(User user){//可以简写成为这个样子,接到异常自动向外抛,如果数据库没有得到提交请求会自动回滚 Session s=null; Transaction tx=null; try{ s=HibernateUtil.getSession();; tx=s.beginTransaction(); s.save(user); tx.commit(); }finally{ if(s!=null) s.close(); } } @Test public void fun1(){ System.out.println(getUser(1)); } public static User getUser(int id){ Session s=null; User user=null; try{ s=HibernateUtil.getSession(); user=(User) s.get(User.class, 1); // user=(User) s.load(User.class,1);//这里会报错 }finally{ if(s!=null) s.close(); } return user; } } public static void add(Object entity){ Session s=null; Transaction tx=null; try{ s=getSession(); tx=s.beginTransaction(); s.save(entity); tx.commit(); }catch(HibernateException e){ tx.rollback(); throw e; }finally{ if(s!=null) s.close(); } } public static void delete(Object entity){ Session s=null; Transaction tx=null; try{ s=getSession(); tx=s.beginTransaction(); s.delete(entity); tx.commit(); }catch(HibernateException e){ tx.rollback(); throw e; }finally{ if(s!=null) s.close(); } } public static void update(Object entity){ Session s=null; Transaction tx=null; try{ s=getSession(); tx=s.beginTransaction(); s.update(entity); tx.commit(); }catch(HibernateException e){ tx.rollback(); throw e; }finally{ if(s!=null) s.close(); } } public static Object get(Class clazz,Serializable id){ Session s=null; try{ s=getSession(); return s.get(clazz, id); }catch(HibernateException e){ throw e; }finally{ if(s!=null) s.close(); } } public static Object load(Class clazz,Serializable id){ Session s=null; try{ s=getSession(); return s.load(clazz, id); }catch(HibernateException e){ throw e; }finally{ if(s!=null) s.close(); } }
关于load()和get()的区别:
两者都是根据类的字节码文件和ID得到一条数据。区别在于:
第一点是:没有记录的情况下,load会抛出异常,get会返回空,一般采用的load方法。
第二点是:get只返回实体对象实例。而load返回的是代理类实体对象实例。
第三点是:get方法只能使用一级缓存。而load可以使用一级和二级缓存。
第四点是:都是通过id得到单个对象的方法。
第五点:load方法具有懒加载的特性,不是立即操作数据库,而是返回一个代理对象,在操作该对象的属性的时候才操作数据库将信息填入。
关于save()和persist()的区别:
在不开启事务的情况下,save方法会先插入数据再回滚,而persist方法不会插入记录
update、saveOrUpdate、merge的区别见我的其他博客:
http://www.cnblogs.com/aigeileshei/p/5796788.html
前面学习了增删改和根据id进行查询。但是查询语句往往比较复杂,hibernate提供了两种方式进行数据库表的查询操作:HQL和Criteria
HQL:
面向对象的查询语言,与SQL不同,HQL中的对象名是区分大小写的(除了JAVA类和属性其他部分不区分大小写);HQL中查的是对象而不是表,而且支持多态;
HQL主要通过Query来操作,Query的创建方式:
Query q=session.createQuery(hql);
Query的主要方法:
list():将query对象中的结果集变成list集合
uniqueResult():将query对象中的结果集变成一个Object对象,当结果集中对象数>1的时候会报异常
setXxx()和getXxx()方法,类似于pstmt的getXxx和setXxx
setFirstResult(number);//设置query查询的结果从第多少条记录开始
setMaxResults(number);//查询的结果多少条。使用上面的和这个方法可以进行分页,而且不限制数据库。这个分页应该是根据方言hibernate封装的
HQL语句中占位符与命名参数的使用:
hql语句中占位符的使用:
String hql="from User as user where user.name=?"; Query query=s.createQuery(hql); query.setString(0,name);
这里注意,下标是从0开始的。
命名参数的使用:
单纯的占位符使用不是很方便,因为每一个?与数据都需要一一对应。hibernate提供了命名参数。
String hql="from User as user where user.name=:n"; Query query=s.createQuery(hql); query.setString("n"name);
同一个命名参数可以多次使用
命名参数在hql中=:命名参数名。格式注意正确。
将命名参数设置进Query中们可以使用后Map结合如果参数过多的话,这样比较简便一些:
static void qr(){ Session s=HibernateUtil.getSession(); String hql="from User where name=:name and age>:bj and (age-:bj)>0"; Query query=s.createQuery(hql); Map <String,Object> params=new HashMap<String,Object>(); params.put("name", "guodaxia"); params.put("bj",12); query.setProperties(params); List<User> users=query.list(); }
hql查询的简单例子:
package cn.itcast.hibernate; import java.util.Date; import java.util.Iterator; import java.util.List; import org.hibernate.Query; import org.hibernate.Session; import cn.itcast.hibernate.domain.User; public class QueryTest { public static void main(String[] args) { User user=new User(); user.setBirthday(new Date()); user.setName("name"); HibernateUtil.add(user); System.out.println(query("name")); } static User query(String name){ Session s=null; try{ s=HibernateUtil.getSession(); // String hql="from User as user where user.name=?"; String hql="from User as user where user.name=:n"; Query query=s.createQuery(hql); // query.setString(0, name);//下标从0开始 query.setString("n", name); //设置结果集的范围,可用来分页 query.setFirstResult(200); query.setMaxResults(10); List<User> list=query.list();//executeQuery() User user=(User) query.uniqueResult(); // for(Iterator<User> it=list.iterator();it.hasNext();){ // User user=it.next(); // list.add(user); //// System.out.println(user); // } // return list.get(0); return user; }finally{ if(s!=null) s.close(); } } }
Criteria(条件查询):
是一种比hql更加面向对象的一种方式。
创建方式:
Criteria crit=session.createCriteria(User.class);
条件查询关于条件的添加与query不一样,在处理结果集方面与query基本一致。
简单属性条件如:
criteria.add(Restrictions.eq(propertyName,value)),
criteria.add(Restrictions.eqProperty(propertyName,otherPropertyName))
Restrictions对象中封装了许多条件查询的增加条件的方法。可以配合API使用
Criteria查询的小例子:
package cn.itcast.hibernate; import java.util.Date; import java.util.List; import org.hibernate.Criteria; import org.hibernate.Session; import org.hibernate.criterion.Restrictions; import cn.itcast.hibernate.domain.User; public class Cri { public static void main(String[] args) { cri("name"); } static void cri(String name){ Session s=null; try{ s=HibernateUtil.getSession(); Criteria c=s.createCriteria(User.class);//条件查询,很面向对象的方式。这个接口相当于一个容器 c.add(Restrictions.eq("name", name));//添加约束条件 c.add(Restrictions.lt("birthday", new Date())); c.setFirstResult(0); c.setMaxResults(10); List<User> list=c.list(); User u=(User)c.uniqueResult(); System.out.println(u); for(User user:list){ System.out.println(user.getName()); } }finally{ if(s!=null) s.close(); } } }