简单使用
三、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);
}