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();
        }
    } 
View Code

 

关于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();
        }
    }
}
View Code

 

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();
        }
    }
}
View Code

 

posted @ 2016-08-22 20:44  guodaxia  阅读(207)  评论(0编辑  收藏  举报