簡單使用
三、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);
}