本文章只是自己在學(xué)習(xí)中記的筆記(可能有點(diǎn)亂),只提供參考截驮。如有錯(cuò)誤請(qǐng)指出
什么是jpa
JPA (Java Persistence API)Java持久化API。是一套Sun公司Java官方制定的ORM方案,是規(guī)范际度,是標(biāo)準(zhǔn) 葵袭,sun公司自己并沒有實(shí)現(xiàn)
-
ORM是什么
?
對(duì)象關(guān)系映射
,ORM是一個(gè)實(shí)現(xiàn)使用對(duì)象操作數(shù)據(jù)庫的設(shè)計(jì)思想
乖菱,主要目的是操作實(shí)體類就相當(dāng)于操作數(shù)據(jù)庫坡锡。不再重點(diǎn)關(guān)注sql語句。 -
JPA的實(shí)現(xiàn)者
JPA只是是一套標(biāo)準(zhǔn)窒所。它只是一套實(shí)現(xiàn)ORM理論的接口鹉勒。沒有實(shí)現(xiàn)的代碼。那么我們必須要有具體的實(shí)現(xiàn)者才可以完成ORM操作功能的實(shí)現(xiàn)吵取!
市場上的主流的JPA框架(實(shí)現(xiàn)者)有:
- Hibernate (JBoos)
- EclipseTop(Eclipse社區(qū))
- OpenJPA (Apache基金會(huì))
Hibernate實(shí)現(xiàn)
hibernate是一個(gè)開放源碼的對(duì)象關(guān)系映射框架
它對(duì)jdbc進(jìn)行了非常輕量級(jí)的對(duì)象封裝禽额。
它將實(shí)體類與數(shù)據(jù)庫表建立映射關(guān)系,是一個(gè)全自動(dòng)的orm框架。
案例說明
對(duì)用戶的增刪改查操作
-
項(xiàng)目搭建
導(dǎo)入對(duì)應(yīng)的maven坐標(biāo)
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-entitymanager --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>5.4.10.Final</version> </dependency> <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-c3p0 --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-c3p0</artifactId> <version>5.4.10.Final</version> </dependency> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.19</version> </dependency> <!-- https://mvnrepository.com/artifact/log4j/log4j --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> <scope>provided</scope> </dependency>
-
配置相關(guān)的jpa配置文件
配置文件在類路徑下的一個(gè)叫
META-INF
的文件下脯倒。-
它的文件命名也有要求实辑。叫persistence.xml
<?xml version="1.0" encoding="UTF-8"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0"> <!-- 持久化單元,name 持久化單元名稱 transaction-type事務(wù)管理的方式 RESOURCE_LOCAL: 本地事務(wù)管理 JPA:分布式事務(wù)管理 --> <persistence-unit name="myJpa" transaction-type="RESOURCE_LOCAL"> <!-- jpa的實(shí)現(xiàn)方式 --> <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> <!-- <class>com.wlm.pojo.Customer</class>--> <!-- 數(shù)據(jù)庫信息 --> <properties> <property name="javax.persistence.jdbc.user" value="root"/> <property name="javax.persistence.jdbc.password" value="123"/> <property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/> <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/website?serverTimezone=UTC&useUnicod=true&characterEncoding=utf-8"/> <!-- 可配置藻丢,配置jpa實(shí)現(xiàn)放的配置信息,也就是hibernate 顯示sql 自動(dòng)創(chuàng)建數(shù)據(jù)庫表: create:程序運(yùn)行時(shí)創(chuàng)建數(shù)據(jù)庫表(如果有表剪撬,先刪除再創(chuàng)建) ipdate:程序運(yùn)行時(shí)再創(chuàng)建表(如果有表不會(huì)創(chuàng)建) none:不會(huì)創(chuàng)建表 --> <property name="hibernate.show_sql" value="true"/><!-- 顯示sql--> <property name="hibernate.hbm2ddl.auto" value="update"/><!--自動(dòng)創(chuàng)建數(shù)據(jù)庫表--> <!-- <property name = "hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" /><!–方言–>--> </properties> </persistence-unit> </persistence>
-
<persistence-unit name="myJpa" transaction-type="RESOURCE_LOCAL">
配置持久化數(shù)據(jù)單元。- name是 持久化單元名稱悠反,名稱可以隨便寫残黑,后面我們?cè)诔绦蛑芯褪歉哌@名稱獲取對(duì)象。
- transaction-type事務(wù)管理的方式斋否,它有2個(gè)選項(xiàng):
- RESOURCE_LOCAL: 本地事務(wù)管理萍摊。
- JPA: 分布式事務(wù)管理。
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
jpa的實(shí)現(xiàn)方式如叼。因?yàn)閖pa是接口冰木,是規(guī)范,它沒有對(duì)數(shù)據(jù)庫的操作的實(shí)現(xiàn)笼恰。所以我們還要選擇是那種方法實(shí)現(xiàn)jpa操作踊沸。這里是選用了hibernate方式。-
<properties>
里配置的是數(shù)據(jù)庫信息社证。注意:其中數(shù)據(jù)庫的信息字段逼龟,都要以
javax.persistence.jdbc.
開頭。
-
再后面2個(gè)屬性追葡,可配可不配腺律,它是配置jpa實(shí)現(xiàn)放的配置信息,也就是hibernate。
重點(diǎn)說下`hibernate.hbm2ddl.auto`宜肉,自動(dòng)創(chuàng)建數(shù)據(jù)庫表匀钧。它有3個(gè)可選對(duì)象。
- create:程序運(yùn)行時(shí)創(chuàng)建數(shù)據(jù)庫表(如果有表谬返,先刪除再創(chuàng)建)
- update:程序運(yùn)行時(shí)再創(chuàng)建表(如果有表不會(huì)創(chuàng)建)
- none:不會(huì)創(chuàng)建表之斯。
-
創(chuàng)建實(shí)體類
@AllArgsConstructor @NoArgsConstructor @Setter @Getter @ToString //--------上面是lombok的注解-------- @Entity @Table(name="User") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private Integer id; private String name; private String pwd; @Column(name = "create_time") private Date createTime; }
注意:上面我用到了lombok。還有遣铝,所有的非lombok注解都是
javax.persistence.*
里的上面的注解是配置映射關(guān)系佑刷。映射關(guān)系的配置有兩個(gè)方向:
- 實(shí)體類和表的映射:
- @Entity:聲明此類是一個(gè)實(shí)體類。
- @Table(name="User"):對(duì)應(yīng)的是數(shù)據(jù)庫中的表酿炸。name就是數(shù)據(jù)庫中的表名
- 實(shí)例類中屬性和表中的字段映射:
- @Id:主鍵瘫絮。
- @GeneratedValue(strategy = GenerationType.IDENTITY):定義的主鍵生成策略,其中有:
- GenerationType.IDENTITY:自增填硕。底層數(shù)據(jù)庫必須支持自增才可以使用麦萤。像mysql。
- GenerationType.SEQUENCE:序列。底層數(shù)據(jù)庫必須支持序列才可以使用频鉴,像orac就支持栓辜,mysql不支持
- GenerationType.TABLE:jpa提供的一種機(jī)制,它通過一張表的形式完成自增操作垛孔。(會(huì)在數(shù)據(jù)庫中創(chuàng)建一張表)藕甩,通過這張表來維護(hù)自增
- GenerationType.AUTO:程序自動(dòng)的選擇主鍵策略。根據(jù)自己的表或運(yùn)行環(huán)境選擇上面三種策略周荐。
- @Column(name = "id"):表中的字段映射狭莱,name,數(shù)據(jù)庫中對(duì)應(yīng)的字段名概作。
- 實(shí)體類和表的映射:
-
api操作
-
增加操作
@Test public void test() { //1.加載配置文件創(chuàng)建工廠(實(shí)體管理類工廠)對(duì)象,傳入的是持久化數(shù)據(jù)單元腋妙,也就是配置文件里我們配置的數(shù)據(jù)單元。 EntityManagerFactory jpa = Persistence.createEntityManagerFactory("myJpa"); //2.通過工廠獲取實(shí)體管理器 EntityManager manager = jpa.createEntityManager(); //獲取事務(wù)對(duì)象 EntityTransaction tx = manager.getTransaction(); tx.begin();//開啟事務(wù) //完成增刪改查 User User = new User(); user.setName("nihao"); user.setPwd("123"); user.setCreateTime(new Date()); //保存 manager.persist(user);//保存操作 //提交事務(wù) tx.commit(); //關(guān)閉資源 manager.close(); jpa.close(); }
-
-
根據(jù)id查詢用戶
引入一個(gè)概念讯榕,上面頻繁通過工廠獲取實(shí)體管理器骤素,是一個(gè)比較耗資源和耗時(shí)的操作。所以我們可以把它放到一個(gè)靜態(tài)代碼塊中愚屁,封裝成一個(gè)工具類來獲取济竹,解決耗資源和耗時(shí)問題
public class JpaUtils { private static EntityManagerFactory factory; static { factory = Persistence.createEntityManagerFactory("myJpa"); } /*獲取實(shí)體類管理器對(duì)象*/ public static EntityManager getEntityManager(){ return factory.createEntityManager(); } }
那么我們根據(jù)id查詢代碼實(shí)現(xiàn):
@Test public void test2() { //獲取EntityManager對(duì)象 EntityManager entityManager = JpaUtils.getEntityManager(); //查詢不需要事務(wù),所以不用開啟事務(wù)霎槐。 //根據(jù)id查詢操作 /* * 要傳入2個(gè)參數(shù) * class:查詢數(shù)據(jù)的結(jié)果需要包裝的實(shí)體類型的字節(jié)碼 * id:查詢的主鍵的信息 * */ // User user = entityManager.find(User.class, 1);//查詢的第一種方法find(); User user = entityManager.getReference(User.class, 1);//第二種方法送浊。參數(shù)代表的類型都一樣。 /* * 這2種方法的區(qū)別有什么不一樣丘跌? * find():查詢的對(duì)象就是當(dāng)前Userr本身袭景。再調(diào)用的時(shí)候,sql發(fā)送的時(shí)機(jī)是立刻去數(shù)據(jù)庫查詢 * getReference():查詢的對(duì)象是一個(gè)代理類對(duì)象闭树。sql發(fā)送的時(shí)機(jī)是什么時(shí)候調(diào)用耸棒,就什么時(shí)候發(fā)送。 * 一般是使用getReference()蔼啦,延遲加載方式榆纽。 * */ System.out.println(user); //釋放EntityManager資源 entityManager.close(); }
其中
entityManager.find
和entityManager.getReference
的作用和結(jié)果都是一樣的。為啥要定義兩個(gè)方法捏肢?- find():查詢的對(duì)象就是當(dāng)前User本身。再調(diào)用的時(shí)候饥侵,sql發(fā)送的時(shí)機(jī)是立刻去數(shù)據(jù)庫查詢
- getReference():查詢的對(duì)象是一個(gè)代理類對(duì)象鸵赫。sql發(fā)送的時(shí)機(jī)是什么時(shí)候調(diào)用,就什么時(shí)候發(fā)送躏升。(延遲加載)
我們一般是使用getReference()辩棒,延遲加載方式來使用。
-
刪除客戶的操作
@Test public void testRemove() { EntityManager entityManager = JpaUtils.getEntityManager(); //開啟事務(wù) EntityTransaction tx = entityManager.getTransaction(); tx.begin();//開啟事務(wù)的操作 //刪除操作 // 操作步驟 /* * 1,先根據(jù)id查詢到用戶 * 2一睁,傳入查詢到的用戶進(jìn)行刪除 * */ User User = entityManager.getReference(User.class, 2); entityManager.remove(User); tx.commit(); entityManager.close(); }
-
更新操作
@Test public void testUpdate() { EntityManager entityManager = JpaUtils.getEntityManager(); EntityTransaction tx = entityManager.getTransaction(); tx.begin(); User User = entityManager.getReference(User.class, 2); User.setName("我我我我"); //更新操作 entityManager.merge(User); tx.commit(); entityManager.close(); }
如果實(shí)體類中有寫屬性沒值钻弄,那么更新操作后數(shù)據(jù)庫那些字段也會(huì)沒值。
-
查詢所有的操作
@Test public void testFindAll() { EntityManager entityManager = JpaUtils.getEntityManager(); //查詢?nèi)縥qpl /* * jqpl:form User * sql:select * from User * */ String jpql = "from User"; Query query = entityManager.createQuery(jpql); //發(fā)送查詢者吁,并封裝結(jié)果集 List<User> list = query.getResultList(); for (User o : list) { System.out.println(o); } entityManager.close(); }
這里引入了一個(gè)jpql
sql:是查詢表和表中的字段窘俺。
jpql:是查詢的實(shí)體類和類中的屬性
它們兩的語法相識(shí)。
比如:
jqpl:form User sql:select * from User
-
倒序查詢?nèi)坑脩舾吹剩鶕?jù)id倒序
EntityManager entityManager = JpaUtils.getEntityManager(); String jpql = "from User order by id desc"; Query query = entityManager.createQuery(jpql); List<User> resultList = query.getResultList(); for (User User : resultList) { System.out.println(User); } entityManager.close();
-
使用jpql查詢用戶的總數(shù)
@Test public void testCount() { EntityManager entityManager = JpaUtils.getEntityManager(); String jpql = "select count(id) from User "; Query query = entityManager.createQuery(jpql); Object singleResult = query.getSingleResult();//獲取一個(gè)結(jié)果的瘤泪。 System.out.println(singleResult); entityManager.close(); }
-
分頁查詢
EntityManager entityManager = JpaUtils.getEntityManager(); String jpql = "from User"; //1.根據(jù)jpql創(chuàng)建query對(duì)象 Query query = entityManager.createQuery(jpql); //2.對(duì)參數(shù)負(fù)賦值--分頁參數(shù) query.setFirstResult(4);//起始索引,從0開始查育八,不包含0 query.setMaxResults(2);//每頁查詢的條數(shù) List<User> resultList = query.getResultList(); for (User User : resultList) { System.out.println(User); } entityManager.close();
-
條件查詢
@Test public void testLike() { EntityManager entityManager = JpaUtils.getEntityManager(); String jpql = "from User where name like ?1"; //1.根據(jù)jpql創(chuàng)建query對(duì)象 Query query = entityManager.createQuery(jpql); /* * 第一個(gè)參數(shù)是占位符的位置对途,默認(rèn)是1開始 * 第二個(gè)是 取值 * */ query.setParameter(1, "ni%"); List<User> resultList = query.getResultList(); for (User User : resultList) { System.out.println(User); } entityManager.close(); }
在
String jpql = "from User where name like ?1"
中,占位符后是hpa的樣式規(guī)定髓棋,有多個(gè)占位符实檀,比如name like ?1 or pwd = ?2
這樣寫,后面的數(shù)字是你設(shè)置占位符里的值的時(shí)候根據(jù)這數(shù)字去設(shè)置值按声。像query.setParameter(1, "ni%");