简单使用

三、Hibernate的简单使用:

    -- 拷贝jar(lib\required、lib\jpa、lib\optional\c3p0、mysql驱动).

    -- 写全局配置文件hibernate.cfg.xml放在src目录下.

       cfg: Configuration.

    -- 编程:

       a. 写持久化类

          持久类 = pojo + annotation注解(@Entity)

      持久类 = pojo + Xxx.hbm.xml文件

        hbm: Hibernate Mapper (配置pojo与表的转换关素).

          pojo : Plain Old Java Object 最简单最传统的java对象.

          写pojo类注意的四点:

      -- 必须有一个无参的构造器.

      -- 所有的属性都要有setter与getter方法.

      -- 属性不能为final修饰.

      -- 要提供一个唯一的标识符.(主键列) @Id

      注意: 持久类名就是表名, 类的属性名就表中的列名.(默认)

拷贝了jar包后,不要忘记add to buildPath

在类上加注解@Entity 主键列加@Id,就是持久化类

测试类

Configuration configuration = new Configuration()//加载src目录的hibernate.properties

.configure();//加载src目录下的hibernate.cfg.xml文件

//第二步:创建SessionFactory

//创建服务注册对象

ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();

SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);

//第三步:获取session

Session session = sessionFactory.openSession();

//第四步:获取事务

Transaction transaction = session.beginTransaction();

//第五步:利用Session完成所有的持久化操作

User u = new User();

u.setId(1);

u.setName("李小华");

u.setAge(18);

//第六步:事务提交或回滚

transaction.commit();

//关闭Session

session.close();

sessionFactory.close();

对象三种状态

@GeneratedValue(strategy=GenerationType.IDENTITY)mysql的自增长策略(oracle用GenerationType.SEQUENCE)

判断是不是持久化状态 session.contains(u)//true持久化状态

a.添加

1.Serializable id = session.save(持久化对象);

    立即 插入数据

2.session.saveOrUpdate(持久化对象);

3.void session.persist(持久化对象);

   -- 延迟往数据库插数据

4.Object obj持久化 = session.merge(脱管);//集成添加与修改

b.根据主键id获取持久化对象

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

//立即查询

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

//延迟查询,返回一个代理对象,如果关session再用会出异常

c.修改

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

u.setxxx()//不用update,commit的时候才执行update语句

--脱管

session.saveOrUpdate(u);

User user = (User)session.merge(u);

session.update(u);

d.删除

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

session.delete(u);

操作一级缓存:

1.判断:session.contains(u);

2.踢出:session.evict(u);

3.清空:session.clear();

4.同步:session.flush();

5.session.close();

JPA注解:

@Table(name="USER",//表名

       schema="",//指定数据库

       indexes={@Index(columnList="name",name="IDX_NAME"),

                @Index(columnList="age",name="IDX_AGE")},//数组使用花括号,指定索引

       uniqueConstraints={@UniqueConstraint(columnNames={"name","phone"},name="UC_NAME_PHONE")}//联合唯一约束

       )

class User

写在类上面的hibernate注解:

@DynamicInsert(true)//动态插入

@DynamicUpdate(true)//动态修改

@SelectBeforeUpdate(true)//修改前先查询,没发生改变就不生成update语句

二、主键映射

a.主键自增长策略:

-- @GeneratedValue(strategy=GenerationType.IDENTITY)

-- @GeneratedValue(strategy=GenerationType.SEQUENCE)

-- @GeneratedValue(strategy=GenerationType.AUTO)推荐

-- @GeneratedValue(strategy=GenerationType.TABLE)//单独生成一张表来维护主键

b.单个属性做主键

--直接在属性上加@Id

c.多个属性做主键

--多个属性上加@Id

@Entity @Table(name="EMP_INFO")

public class Employee implements Serializable{//联合主键必须实行序列化接口

    @Id

    private String lastName;

    @Id

    private String firstName;

    private int age;

}

d.复合属性

持久化类里@EmbeddedId//复合属性做主键,此对象也要实现序列化接口

三、基本属性映射

@Column

-- columnDefinition

-- length:长度

-- name:列名

-- nullable:非空约束

-- precision:总位数

-- scale:小数点后面的位数(跟上一个结合使用,java类型是BigDecemal)

-- unique:唯一约束

-- insertable:是否允许插入

-- updatable:是否允许修改

要弄默认值,需要动态插入,以及用包装类

@Temporal:修饰日期属性

-- TemporalType.DATE      yyyy-MM-dd

-- TemporalType.TIME      HH:mm:ss

-- TemporalType.TIMESTAMP 

@Lob//大的二进制或文本

@Basic(fetch=FetchType.LAZY)//延迟加载

private byte[] picture;

FileInputStream fis = new FileInputStream("C:\\User\\Administrator\\Picture\\SamplePicture\\Koala.jpg");

byte[] data = new byte[fis.available()];

fis.read(data);

fis.close();

u.setPicture(data);

可能数据库有大小限制,要改my.ini文件

private transient String tel;//@Transient或者transient关键字指定不是持久化的属性

@Basic:延迟加载属性

  - fetch

    FetchType.LAZY//延迟加载

    FetchType.EAGER//立即加载

1对多,1的一端做主表,多的一端做从表。

复合属性映射

@Embedded //复合属性(内含的)

说明:意思是属性是 非基本类型

@AttributeOverrides:属性重新命名(少用)

@AttributeOverrides({

    @AttributeOverride( name="firstName",column=@Column(name="FIRST_NAME") ),//复合属性更改列名

    @AttributeOverride( name="lastName",column=@Column(name="LAST_NAME") )

})

代替方法:在那个类里的属性上写 @Column(name="F_NAME")

集合映射

会单独生成一张表。要面向接口编程并且集合属性要程序员自己初始化。

private List<String> lists = new ArrayList<String>();

1.List集合2.Map集合3.Set集合

公共的注解:

@ElementCollection(fetch=FetchType.LAZY,targetClass=String.class) 元素是集合

                    指定延迟加载 集合映射出来的表

@CollectionTable(name="ADD_INFO",foreignKey = @ForeignKey(name="FK_ADD_USER")) 集合映射出来的表

                  表名 外键约束名

1.List集合(有序): 要在属性上加 @OrderColumn() 排序列

    -- List<String>

    -- List<Address>

    Address复合属性这个类上面需要加 @Embeddable

public class User{

    @Id @GeneratedValue(strategy=GenerationType.AUTO)

    @Column(name="U_ID")

    private int id;

    @Column(name="U_NAME", length=30,nullable=false)

    private String name;

    @Column(name="U_AGE",nullable=false)

    private int age;

    @ElementCollection(fetch=FetchType.LAZY,targetClass=String.class)//targetClass指的是集合的元素类型

    @CollectionTable(name="ADD_INFO",

                    foreignKey = @ForeignKey(name="FK_ADD_USER"),//更改外键约束名

                    joinColumns=@joinColumn(name="USER_ID",REFERENCEDcOLUMNnAME="U_ID"))//改外键列名

    @OrderColumn(name="O_ID")//排序列

    private List<String> addresses = new ArrayList<>();

}

    java代码:

    //利用Session完成所有的持久化操作

    User u = new User();

    u.setAge(18);

    u.setName("李小一");

    u.getAddresses().add("天河区");

    u.getAddresses().add("海珠区");

    session.save(u);

执行完后,生成了USER_INFO表和ADD_INFO表

USER_INFO表

U_ID  U_AGE  U_NAME

1     18     李天一

ADD_INFO表结构是

外键列  addresses  O_ID

1        天河区    0

1        海珠区    1

ADD_INFO表的主键列:【外键列 + 排序列】做联合主键

同样地,集合是对象类型的,要在这个类的上面加@Embeddable

2.Map集合 @MapKeyColumn() key生成的列

    -- Map<String, String>

    -- Map<String, Address>

    Address复合属性需要加 @Embeddable

 public class User{

    @Id @GeneratedValue(strategy=GenerationType.AUTO)

    @Column(name="U_ID")

    private int id;

    @Column(name="U_NAME", length=30,nullable=false)

    private String name;

    @Column(name="U_AGE",nullable=false)

    private int age;

    @ElementCollection(fetch=FetchType.LAZY,targetClass=String.class)//targetClass指的是集合的元素类型

    @CollectionTable(name="ADD_INFO",

                    foreignKey = @ForeignKey(name="FK_ADD_USER"),//更改外键约束名

                    joinColumns=@joinColumn(name="USER_ID",REFERENCEDcOLUMNnAME="U_ID"))//改外键列名

    //map的key

    @MapKeyColumn(name="MAP_KEY")

    private Map<String, String> addresses = new HashMap<>();

}

    java代码:

    //利用Session完成所有的持久化操作

    User u = new User();

    u.setAge(18);

    u.setName("李小一");

    u.getAddresses().put("100000","天河区");

    u.getAddresses().put("200000","海珠区");

    session.save(u);

      用户表(user_info):

      U_ID  U_AGE U_NAME

      1      18   李小一

      集合映射出来的表(add_info):

      USER_ID  addresses  MAP_KEY

      1        天河区     100000

      1        海珠区     200000

      说明:USER_ID是外键,主键列:【外键列 + Map的key对应的列】

3.Set集合 (无序列)

    -- Set<String>

    -- Set<Address> -->在属性上加 @Column(name="A_NAME",nullable=false) 外键和这几个联合作主键

    Address复合属性需要加 @Embeddable

      //加非空约束,才有主键列(默认没主键列)

      @Column(nullable=false)

      private Set<String> addresses = new HashSet<>();

      java代码:

        //利用Session完成所有的持久化操作

        User u = new User();

        u.setAge(18);

        u.setName("李小一");

        u.getAddresses().add("天河区");

        u.getAddresses().add("海珠区");

        session.save(u);

      用户表(user_info):

      U_ID   U_AGE  U_NAME

      1      18     李小一

      集合映射出来的表(add_info):

      USER_ID addresses

      1       天河区

      1       海珠区

      说明:主键列:【外键列 + set集合元素列】

-------------------------------------------------------------

关联映射(重点)

   -- 双向关联(1-N):(两边都加注解)

   1的一端(主表)

   N的一端(从表)

@Entity @Table(name="TEA_INFO")

public class Teacher{

    private int id;

    private String name;

    private String job;

    @OneToMany(fetch=FetchType.LAZY,//延迟加载

               targetEntity=Student.class,//关联持久化类

           cascade=CascadeType.REMOVE, //级联删除(级联到关联的实体),一般在主表配置,在从表也可(老师没数据时会被删)

           orphanRemoval=true,//删除孤儿记录(主表从表断绝关系)

           mappedBy="teacher") //代表哪边维护关联关系,写关联的实体中哪个引用了它自己的那个属性

    private Set<Student> students = new HashSet<>();//1的一端

}

@Entity @Table(name="STU_INFO")

public class Student{

    private int id;

    private String name;

    private int age;

    @ManyToOne(fetch=FetchType.LAZY, //延迟加载

               targetEntity=Teacher.class // 关联的实体

           )

    @JoinColumn(name="T_ID",referencedColumnName="TEA_ID") //指定外键列

    private Teacher teacher;

}

说明:1的一端属性写另外的集合,多的一端写指向1的端的属性.

(表里面生成有外键列,外键列那端就是多的一端——李小华语)。1的一端(加了mappedBy一端)不维护关联关系

测试代码:

Teacher t1 = new Teacher();//主表

t1.setName("唐僧");

t1.setJob("长老");

session.save(t1);

Student s1 = new Student(); //从表

s1.setAge(500);

s1.setName("孙悟空");

s1.setTeacher(t1);

Student s2 = new Student(); //从表

s2.setAge(500);

s2.setName("猪八戒");

s2.setTeacher(t1);

说明:先保存主表,再保存从表

tea_info

TEA_ID  TEA_JOB  TEA_NAME

1       长老     唐僧

stu_info是多的一端

STU_ID  STU_AGE  STU_NAME  T_ID

1       500      孙悟空    1

2       500      猪八戒    1

查询(测试延迟加载):

Teacher t1 = (Teacher)session.get(Teacher.class,1);

Set<Student> students = t1.getStudents();

Iterator<Student> iter = students.iterator();

while(iter.hasNext()){

    Student s = iter.next();

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

}

删除:

session.delete(t1);

说明:配置级联删除,只删老师,也会删学生。级联删除在主表里面配置。如果在从表配置是不科学(把某老师的学生删掉同时就删了那老师,不科学)

t1.getStudents().clear();//把从表关联的记录全部删除

说明:要在主表 @OneToMany注解里配orphanRemoval=true,//删除孤儿记录(主表从表断绝关系)

------------N-N(多对多)-------------

@ManyToMany()

@Entity @Table(name="TEA_INFO")

public class Teacher{

    private int id;

    private String name;

    private String job;

    @ManyToMany(fetch=FetchType.LAZY,//延迟加载

               targetEntity=Student.class,//关联持久化类

           cascade=CascadeType.REMOVE, //级联删除(级联到关联的实体)

           mappedBy="teachers") //代表哪边维护关联关系,写关联的实体中哪个引用了它自己的那个属性

    private Set<Student> students = new HashSet<>();//1的一端

}

@Entity @Table(name="STU_INFO")

public class Student{

    private int id;

    private String name;

    private int age;

    @ManyToMany(fetch=FetchType.LAZY, //延迟加载

               targetEntity=Teacher.class // 关联的实体

           )

    // 生成中间表

    @JoinTable(name="STU_2_TEA",

              joinColumns= @JoinColumn(name="S_ID",referencedColumnName="STU_ID"),//没有加mappedBy属性的一端

              inverseJoinColumns= @JoinColumn(name="T_ID",referencedColumnName="TEA_ID")) //加了mappedBy属性的一端

    private Set<Teacher> teachers = new HashSet<>();

}

(STU_2_TEA)表

S_ID  T_ID

1     1

2     1

-----------------1-1 -----------------

双向关联

1-1

说明:1.两边都用 @OneToOne

      2.两边属性都用关联的实体定义

@Entity @Table(name="TEA_INFO")

public class Teacher{

    private int id;

    private String name;

    private String job;

    @OneToOne(fetch=FetchType.LAZY,//延迟加载

               targetEntity=Student.class,//关联持久化类

           cascade=CascadeType.REMOVE, //级联删除(级联到关联的实体)

           orphanRemoval=true,//删除孤儿记录(主表从表断绝关系)

           mappedBy="teacher") //代表哪边维护关联关系,写关联的实体中哪个引用了它自己的那个属性

    private Student student;

}

@Entity @Table(name="STU_INFO")

public class Student{

    private int id;

    private String name;

    private int age;

    @OneToOne(fetch=FetchType.LAZY, //延迟加载

               targetEntity=Teacher.class // 关联的实体

           )

    @JoinColumn(name="T_ID",referencedColumnName="TEA_ID") //指定外键列

    private Teacher teacher;

}

单向关联(只需要一边能查询)

1-1

1-N(?)

N-1(保留学生这边的注解,删掉老师这端的)

N-N

继承映射

@Entity

@Inheritance(strategy=InheritanceType.SINGLE_TABLE)//生成在一张表中

@DiscriminatorColumn(name="DC",discriminatorType=DiscriminatorType.INTEGER)//辨别者列

@DiscriminatorValue("0")//辨别者列的值

public class Person{

    @Id @Generator()

    private int id;

    private String name;

}

@DiscriminatorValue("1")//辨别者列的值

public class Employee extends Person{

    private double salary;

}

@DiscriminatorValue("2")//辨别者列的值

public class Manager extends Employee{

    private String job;

}

hibernate.cfg.xml配置持久化类

代码:

Manager m = new Manager();

m.setJob("经理");

m.setName("李大华");

m.setSalary(2909.98);

session.save(m);

Employee m = new Employee();

m.setJob("经理");

m.setName("李大华");

m.setSalary(2909.98);

session.save(m);

DC  ID  NAME  SALARY  JOB

2   1   达宏  299     经理

1   2   大华  1       null

都继承在同个表里

第二种方式:

顶级父类:

@Entity

@Inheritance(strategy=InheritanceType.JOINE)//每个类单独生成一张表

第三种方式:

顶级父类:

@Entity

@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)//每个类单独生成一张表

一、HQL查询

Query query = session.createQuery(hql);

分页

第一个?号 query.setFirstResult((pageIndex-1)*pageSize);

第二个?号 query.setMaxResults(pageSize);

实例:

List<Student> students = session.createQuery("from Student as s").list();//from 持久化类名

List<Student> students = session.createQuery("select s from Student as s").list();

List<Object[]> list = session.createQuery("select name,age from Student").list();//查询多列

List<String> list = session.createQuery("select name from Student").list();

List<List<Object>> list = session.createQuery("select new list(name,age) from Student").list();//默认是obj数组,new了就变成list

List<Map<String,Object>> lists = session.createQuery("select new map(name,age) from Student").list();//key默认第一列0,第二列是1

List<Map<String,Object>> lists = session.createQuery("select new map(name as n,age as a) from Student").list();//改key

List<Person> lists = session.createQuery("select new org.fkjava.domain.Person(name,age) from Student").list();//

关联查询实例:

//老师id为1的所有学生(隐式关联,意思是关联的属性是个持久化类)

session.createQuery("select s from Student s where s.teacher.id=?").setInteger(0,1).list();

//关联的属性是集合,要用显式关联

//查学生id为1的老师

Teacher t = session.createQuery("select t from Teacher t inner join t.students as s where s.id = ?").setParameter(0,1).list();

//抓取连接join fetch

List<Student> stus = session.createQuery("select s from Student s join fetch s.teacher").list();

//order by

List<Student> stus = session.createQuery("select s from Student s order by s.age asc")

                            .setFirstResult((pageIndex-1)*pageSize)

                            .setMaxResults(pageSize)

                            .list();

//统计函数,跟sql一样,注意ave(),sum()返回出来接收用Double

//根据老师分组,统计学生的数量

List<Object[]> list = session.createQuery("select count(s),s.teacher.name from Student as s group by s.teacher.id")

//过滤出老师id为2的

Object[] obj = session.createQuery("select count(s),s.teacher.name from Student as s group by s.teacher.id having s.teacher.id=?")

                                .setParameter(0,2).uniqueResult();

session.createQuery("select s from Student s where s.name like ?11")

       .setParameter("11","%小%").list();

二、Criteria查询:完全面向对象(不需要写查询语句)

1.session 2.Criteria criteria = session.createCriteria(持久化类.class)

Criteria 类的方法:

- add(Criterion criterion):添加查询条件

    Criterion:查询对象

    a.Restrictions 生成查询对象的工具类,把where中的运算符,表达式,函数全部改成了静态的方法。

    万能的:sqlRestriction(String sql); // 如果没找到where部分的运算符,表达式,函数,就直接用sqlRestriction(String sql)

    b.Property工具类(生成查询条件)

- addOrder(Order order):排序

- createAlias(String associationPath):关联查询

     创建关联查询后(如果不加别名)添加的查询条件,永远都是为目标持久化类添加的

- createCriteria(String associationPath):关联查询

     创建关联查询后(如果不加别名)添加的查询条件,永远都是为关联持久化类添加的

- setFetchMode(String associationPath):抓取延迟的属性

     FetchMode.JOIN:立即加载

     FetchMode.SELECT:延迟加载

- setProjection(Projection projection):查询哪些列

- 子查询(离线查询)

   相当于定义了一条查询语句

//离线查询

DetachedCriteria dc = DetachedCriteria.forClass(Student.class);

//与session关联起来

Criteria ci = dc.getExecutableCriteria(session);

List<Student> lists = ci.list();

//子查询

List<Student> lists = session.createCriteria(Student.class)

                             .add(Restrictions.in("age",new Object[]{19,20,21})).list();

//子查询和离线查询结合

DetachedCriteria dc = DetachedCriteria.forClass(Teacher.class)

                                      .setProjection(Projections.property("id"));

List<Student> lists = session.createCriteria(Student.class)

                             .add(Property.forName("id").in(dc)).list();

例子1://查询所有学生

List<Student> students = session.createCriteria(Student.class).list();

//添加查询条件

List<Student> students = session.createCriteria(Student.class)

                                .add(Restrictions.like("name","%小%"))

                .add(Restrictions.between("age",20,22))

                .add(Restrictions.sqlRestriction("length(stu_name) = ?",6,StandardBasicTypes.INTEGER))

                                .list();

//排序

List<Student> students = session.createCriteria(Student.class)

                                .addOrder(Order.asc("age")).list();

//查询多列

ProjectionList pl = Projections.projectionList();

pl.add(Projections.property("name"))

  .add(Projections.property("age"));

List<Object[]> lists = session.createCriteria(Student.class)

       .setProjection(pl)

       .list();

//查询指定的列(一列,后面覆盖前面)

List<Object> lists = session.createCriteria(Student.class)

       .setProjection(Projections.property("name"))

       .setProjection(Projections.property("age"))

       .list();

//聚集函数count、max、min、avg

Object count = session.createCriteria(Student.class)

                      .setProjection(Projections.count("id"))

              .uniqueResult();

//分组

session.createCriteria(Student.class)

       .setProjection(Projections.groupProperty("teacher.id")).list();

//创建关联

List<Student> lists = session.createCriteria(Student.class)

                             .createAlias("teacher","t")//创建关联查询

                 .add(Restrictions.eq("t.id",1)).list();

说明:如果下边查询条件不取别名,默认是目标持久化类(Student.class)的条件

//createCriteria :创建关联

List<Student> lists = session.createCriteria(Student.class)

                             .createCriteria("teacher")创建关联查询

                 .add(Restrictions.e q("id",1)).list();//添加查询条件是Teacher的

//两个对象都添加查询条件createAlias

List<Student> lists = session.createCriteria(Student.class)

                             .createAlias("teacher","t")//创建关联查询

                 .add(Restrictions.between("age",10,20))//学生

                 .add(Restrictions.eq("t.id",1)).list();//添加查询条件是Teacher的

//两个对象都添加查询条件createCriteria

List<Student> lists = session.createCriteria(Student.class,"s")

                             .createCriteria("teacher")//创建关联查询

                 .add(Restrictions.between("s.age",10,20))//学生

                 .add(Restrictions.eq("id",1)).list();//添加查询条件是Teacher的

//抓取延迟加载

List<Student> lists = session.createCriteria(Student.class)

                 .setFetchMode("teacher",FetchMode.JOIN).list();

三、原生的SQL查询:写sql进行查询

a.session

b.写sql

c.SQLQuery sqlQuery = session.createSQLQuery(sql);

SQLQuery中的方法:

  - addEntity(Class entityType) : 实体查询

  - addJoin(String tableAlias, String path) : 关联查询

  - addScalar(String columnAlias) : 标量查询

  - 命名查询(sql命名查询)

  第一种方式:使用步骤:

    a.给个配置文件,定义hql语句

      xxx.hbm.xml

      <sql-query name="起个名字">hql语句</sql-query>

    b.在hibernate.cfg.xml文件进行配置

      <mapping resource="org/fkjava/domain/Query.hbm.xml"/>

    c.使用:Query query = session.getNamedQuery("sql语句的名字");

    例子:

    Query.hbm.xml文件

    <hibernate-mapping>

        <!--定义sql语句-->

    <sql-query name="sql-query_1">

        select s.*,t.* from stu_info as s,tea_info as t where s.t_id = t.tea_id

        <!--实体查询:addEntity-->

        <return alias="s" class="org.fkjava.domain.Student"></return>

        <return alias="t" class="org.fkjava.domain.Teacher"></return>

        <!--关联查询:addJoin-->

        <return-join alias="t" property="s.teacher"/>

        <!--标量查询:addScalar-->

        <return-scalar column="s.stu_age"/>

    </sql-query>

    </hibernate-mapping>

    //命名查询

    session.getNamedQuery("sql-query_1");

  第二种方式:(加注解)

    a.在持久化类上加注解

      @NamedNativeQuery(name="sql_query_2",resultSetMapping="rs", query="查询语句")

      @SqlResultSetMapping(name="rs",entities={ @EntityResult(entityClass=Student.class), // 实体查询

                                                @EntityResult(entityClass=Teacher.class)},

                                     columns={ @ColumnResult(name="s.stu_age")}) // 标量查询

    说明:下面的注解是关于rs结果集映射的

    b.配置

      <mapping class="org.fkjava.domain.Teacher"/>

    c.使用:Query query = session.getNamedQuery("hql语句的名字");

    List<Object[]> lists = query.list();

    for(Object[] obj : lists){

    System.out.println(obj.length);

    System.out.println(obj[0] + "==" + obj[1] + "==" + obj[2]);

    }

  - 调用存储过程

  <sql-query name="call_proc">

    {call proc_query(?)}

    <return class="org.fkjava.domain.Student"></return>

  </sql-query>

在数据库创建存储过程:

DELIMITER $

CREATE PROCEDURE proc_query(IN minAge INT)

BEGIN

   select * from stu_info where stu_age > minAge;

END

$

//调用存储过程

List<Student> students = session.getNamedQuery("call_proc").setParameter(0,20).list();

for(Student stu : students){

    System.out.println(stu.getName() + "==" + stu.getAge());

}

//使用SQLQuery直接写存储过程sql

List<Student> students = session.createSQLQuery("{call proc_query(?)}")

                                .addEntity(Student.class).setParameter(0,20).list();

for(Student stu : students){

    System.out.println(stu.getName() + "==" + stu.getAge());

}

//addEntity() : 实体查询

List<Student> students = session.createSQLQuery("select * from stu_info")

                                .addEntity(Student.class).list();

//关联

List<Object[]> lists = session.createSQLQuery("select s.*, t.* from stu_info as s,tea_info as t where s.t_id = t.tea_id")

                              .addEntity("s",Student.class)

                  .addEntity("t",Teacher.class)

                  .list();

//查两列

List<Object[]> lists = session.createSQLQuery("select stu_name, stu_age from stu_info").list();

//addScalar() : 标量查询

List<Object[]> lists = session.createSQLQuery("select * from stu_info")

                              .addScalar("stu_name") // 标量查询

                  .addScalar("stu_age").list();

//addJoin(String tableAlias, String path) : 关联查询

List<Object[]> lists = session.createSQLQuery("select s.*, t.* from stu_info as s,tea_info as t where s.t_id = t.tea_id")

                              .addEntity("s",Student.class) //实体查询

                  .addEntity("t",Teacher.class)

                  .addJoin("t","s.teacher") // 关联查询

                  .addScalar("s.stu_age") // 标量查询

                  .list();

说明:关联查询就是把t放到s.teacher这个属性里面去。Student里面teacher属性就有值了。

=========================================

########## HQL语句写法 ##########

1.from 字句

from Student [as s]

2.select 字句

查询对象:select s from Student as s 返回类型是List<Student>

查询多列:select s.id,s.age from Student as s 返回类型是List<Object[]>

     select id,age from Student 返回类型是List<Object[]>

     select s,s.name,s.age from Student as s 返回类型是List<Object[]>

查询一列:select name from Student 返回类型是List<String>

3.select new 字句(可以改变返回的List集合中元素存放的是什么)

select new list():List<List<>>

select new map():List<Map<>>

select new User():List<User>

举例:

select new list(name,age) from Student 返回类型是List<List<Object>>,已经不是List<object[]>

select new map(name,age) from Student 返回类型是List<Map<String,Object>>,默认第一个的key为0,第二个为1等等

select new map(name as n,age as a) from Student 这时key就变为 n 和 a

select new org.fkjava.domain.Person(name,age) from Student 返回类型是List<Person>

4.关联查询(对象)

-- 隐式关联: @ManyToOne 、 @OneToOne

   关联的属性是一个持久化类

-- 显式关联: @OneToMany 、 @ManyToMany

   关联的属性是一个集合

类之间的关系:学生类有一个老师的属性,老师类有一个装学生的集合

问题来了:现在有一个需求,查老师id为1的学生,就是关联查询

select s from Student as s where s.teacher.id = ?

session.createQuery(hql).setInteger(0,1).list();//第一个0代表 第一个 ? ,参数值为1

说明:你要查的持久化类关联的属性是实体,就用隐式关联

需求是查学生id为1的老师,要查老师,看里面关联的属性是集合,就得用显式关联

select t from Teacher as t inner join t.students as s where s.id = ?

说明:s就相当于对象了

-- 抓取连接(延迟加载的属性)

select s from Student as s join fetch s.teacher

排序order by

select s from Student as s order by s.age asc

分页

List<Student> students = session.createQuery("select s from Student as s")

.setFirstResult((pageIndex - 1)*pageSize)

.setMaxResults(pageSize)

.list();

聚合函数(统计函数)

Long count = (Long)session.createQuery("select count(*) from Student").uniqueResult();

//可以根据具体数据的类型写返回类型

Integer max = (Integer)session.createQuery("select max(age) from Student").uniqueResult();

Double avg = (Double)session.createQuery("select avg(score) from Student").uniqueResult();

Double sum = (Double)session.createQuery("select sum(score) from Student").uniqueResult();

分组

根据老师分组,统计学生的数量

select count(s),s.teacher.name from Student as s group by s.teacher.id

根据老师分组,统计学生的数量,把老师id为2的过滤出来

select count(s),s.teacher.name from Student as s group by s.teacher.id having s.teacher.id = ?

where 字句

select s from Student as s where s.name like ?11

...setParameter("11","%小%").list();

小结:

from 字句的类后面不取别名,前面就直接写属性名

select new list()意思就是返回的List<List<Object>> 里面泛型是List集合

select new map()里的key默认从0开始,如果想改变key,查询属性取别名即可

select new 数据传输类(包名加类名),这个类要有对应带参构造器

如果查学生,看里面关联属性是什么,是类就隐式,是集合就显式

=======================李韩飞========================

持久化映射文件 *.hbm.xml

<hibernate-mapping>

    <!--name是类名,table是表-->

    <class name="Person" table="t_person">

         <id name="id" column="id">

          <generator class="native"/>

     </id>

     <property name="name" column="t_name"></property>

    </class>

</hibernate-mapping>

连接工厂是线程安全,session非线程安全

一级缓存:clear后就会清掉

批量操作建议的方式:在循环里面

if(i % 10 == 0){

      session.flush();

      session.clear();

}

普通组件和动态组件(在对象的属性是个对象)

<component name="phone">

    <property name="companyPhone" column="t_company_phone"/>

    <property name="homePhone"/>

</component>

即映射到类的对象属性里

动态组件

private Map attribute = new HashMap();

配置文件:

<dynamic-component name="attribute">

    <property name="key1" column="t_key1" type="string" />

    <property name="key2" column="t_key2" type="integer" />

</dynamic-component>

//高效操作map数据

Iterator<Map.Entry> it = p.getAttribute().entrySet().iterator();

for(;it.hasNext();){

     Map.Entry map = it.next();

     System.out.println(map.getKey()+"==="+map.getValue());

}

数组映射

<array name="arrays">

    <key column="id"/> 指person类的id

    <list-index column="indexs"/>

    <element column="values" type="string"></element>

</array>

<!-- Map的映射配置-->

<map name="myMap">

    <key column="id"/> 指person类的id

    <map-key column="map_key"/>

    <element column="values" type="string"></element>

</map>

<!-- set的映射配置-->

<set name="mySet">

    <key column="id"/> 指person类的id

    <element column="values"></element>

</set>

关联映射

<one-to-one name="address"/>

<many-to-one name="" nuique="true" not-null="true"/>

保存数据,要先保存主表,再保存从表。

===============================

=====================项目运用======================

多条件分页查询的dao写法:条件是不确定的,所以hql要拼出来。

public List<User> getUserByPage(User user, PageModel pageModel){

    StringBuilder hql = new StringBuilder();

    hql.append("select u from User as u where 1=1");

    List<Object> params = new ArrayList<>();

    if(user != null){

        if(StringUtils.hasText(user.getName())){

            hql.append(" and name like ? ");

            params.add("%"+user.getName()+"%");

        }

        if(StringUtils.hasText(user.getPhone())){

            hql.append(" and phone like ?");

            params.add("%"+user.getPhone()+"%");

        }

        if(user.getJob()!=null && StringUtils.hasText(user.getJob().getCode())){

            hql.append(" and job.code = ?");

            params.add(user.getJob().getCode());

        }

    }

    hql.append(" order by createDate asc");

    return this.findByPage(hql.toString(), pageModel, params);

}

使用第三种方式要在 userDao实现类里加deleteUser方法:

    public void deleteUser(String[] userIds){

        StringBuilder hql = new StringBuilder();

        hql.append("delete from User where userId in(");

        for(int i = 0;i<userIds.length;i++){

            hql.append( i == 0 ? "?" : ",?");

        }

        hql.append(")");

        this.bulkUpdate(hql.toString(), userIds);

    }

--dao实现类增加方法

    public void checkUser(String[] userIds,Short status){

        StringBuilder hql = new StringBuilder();

        hql.append("update User set status = ?,checker = ?,checkDate = ? where userId in(");

        List<Object> params = new ArrayList<>();

        params.add(status);

        params.add(WebConstant.getSessionUser());

        params.add(new Date());

        for(int i = 0;i<userIds.length;i++){

            hql.append( i == 0 ? "?" : ",?");

            params.add(userIds[i]);

        }

        hql.append(")");

        this.bulkUpdate(hql.toString(), params.toArray());

    }

//批量删除角色

    public void deleteRole(String[] ids){

        StringBuilder hql = new StringBuilder();

        hql.append("delete from Role where id in(");

        Long[] params = new Long[ids.length];//id是long类型要注意

        for(int i=0;i<ids.length;i++){

            hql.append(i==0? "?":",?");

            params[i] = Long.valueOf(ids[i]);

        }

        hql.append(")");

        this.bulkUpdate(hql.toString(),params);

    }

//异步加载树的hql

public List<Object[]> getModuleByCodeAndName() {

    String hql = "select code,name from Module order by code asc";

    return find(hql);

}

---------------------------------

集合映射(对象有个集合)

T_USER

ID  NAME

T_USER_ADDRESS

USER_ID外键 ADDRESS

* 这种是1对多的处理方式

有集合就意味着有额外包含外键的一张表

无序,不重复

order-by属性:order-by="address DESC"(默认ASC)

<set name="addressSet" table="user_addressSet" sort="natural">排序属性,用TreeSet

    <key column="userId"></key>指定名字即可,会自动找主键

    <element type="string" column="address"></element>

</set>

List映射,有序,可重复

<list name="addressList" table="">

    <key column="userId"></key>

    <list-index column="idx"></list-index>

    <element type="string" column=""></element>

</list>

map映射,

<map name="addressMap" table="">

    <key column="userId"></key>

    <map-key type="string" column="key_"></map-key>

    <element type="string" column="address"></element>

</map>

Bag  无序,可重复,用List来引用

<bagname="addressMap" table="">

    <key column="userId"></key>

    <element type="string" column="address"></element>

</bag>

1对多(外键在多的一方)

public class Department{

    private Set<Employee> employees;

}

inverse属性,默认false维护关联关系,true就不维护关联关系

--------------------------------------------------------

=====================项目运用======================

多条件分页查询的dao写法:条件是不确定的,所以hql要拼出来。

public List<User> getUserByPage(User user, PageModel pageModel){

    StringBuilder hql = new StringBuilder();

    hql.append("select u from User as u where 1=1");

    List<Object> params = new ArrayList<>();

    if(user != null){

        if(StringUtils.hasText(user.getName())){

            hql.append(" and name like ? ");

            params.add("%"+user.getName()+"%");

        }

        if(StringUtils.hasText(user.getPhone())){

            hql.append(" and phone like ?");

            params.add("%"+user.getPhone()+"%");

        }

        if(user.getJob()!=null && StringUtils.hasText(user.getJob().getCode())){

            hql.append(" and job.code = ?");

            params.add(user.getJob().getCode());

        }

    }

    hql.append(" order by createDate asc");

    return this.findByPage(hql.toString(), pageModel, params);

}

使用第三种方式要在 userDao实现类里加deleteUser方法:

    public void deleteUser(String[] userIds){

        StringBuilder hql = new StringBuilder();

        hql.append("delete from User where userId in(");

        for(int i = 0;i<userIds.length;i++){

            hql.append( i == 0 ? "?" : ",?");

        }

        hql.append(")");

        this.bulkUpdate(hql.toString(), userIds);

    }

--dao实现类增加方法

    public void checkUser(String[] userIds,Short status){

        StringBuilder hql = new StringBuilder();

        hql.append("update User set status = ?,checker = ?,checkDate = ? where userId in(");

        List<Object> params = new ArrayList<>();

        params.add(status);

        params.add(WebConstant.getSessionUser());

        params.add(new Date());

        for(int i = 0;i<userIds.length;i++){

            hql.append( i == 0 ? "?" : ",?");

            params.add(userIds[i]);

        }

        hql.append(")");

        this.bulkUpdate(hql.toString(), params.toArray());

    }

//批量删除角色

    public void deleteRole(String[] ids){

        StringBuilder hql = new StringBuilder();

        hql.append("delete from Role where id in(");

        Long[] params = new Long[ids.length];//id是long类型要注意

        for(int i=0;i<ids.length;i++){

            hql.append(i==0? "?":",?");

            params[i] = Long.valueOf(ids[i]);

        }

        hql.append(")");

        this.bulkUpdate(hql.toString(),params);

    }

//异步加载树的hql

public List<Object[]> getModuleByCodeAndName() {

    String hql = "select code,name from Module order by code asc";

    return find(hql);

}