ORM思想java
主要目的:操做實體類就至關於操做數據庫表mysql
創建兩個映射關係:實體類和表的映射關係和實體類中屬性和表中字段的映射關係程序員
再也不重點關注sql語句web
實現orm思想的框架:mybatis,hibernatespring
hibernate:一個開放源代碼的對象關係映射框架,它對JDBC進行了很是輕量級的對象封裝,它將POJO與數據庫表創建映射關係,是一個全自動的orm框架,hibernate能夠自動生成sql語句,自動執行,使得java程序員能夠爲所欲爲的使用對象編程思惟來操縱數據庫。sql
JPA規範:數據庫
內部是由接口和抽象類組成編程
優點:api
一、標準化緩存
二、容器級特性的支持
三、簡單方便
四、查詢能力
五、高級特性
入門案例:
一、建立maven工程導入座標
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-c3p0</artifactId> <version>5.0.7.Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>5.0.7.Final</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency> <dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> <version>2.2.11</version> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-core</artifactId> <version>2.2.11</version> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-impl</artifactId> <version>2.2.11</version> </dependency> <dependency> <groupId>javax.activation</groupId> <artifactId>activation</artifactId> <version>1.1.1</version> </dependency> </dependencies>
二、須要配置jpa的核心配置文件
位置:配置到類路徑下的一個叫作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:事務管理方式 JTA:分佈式事務管理 RESOURCE_LOCAL:本地事務管理 --> <persistence-unit name="myJpa" transaction-type="RESOURCE_LOCAL"> <!--JPA的實現方式--> <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> <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.jdbc.Driver"/> <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/ssm?useUnicode=true&characterEncoding=UTF-8"/> <!--可選配置,jpa實現方的配置信息 顯示sql:false|true 自動建立數據庫表:create 程序運行時建立數據庫表(若是有表,先刪除表再建立) update 程序運行時建立表(若是有表,不會建立表)、 none 不會建立表 --> <property name="hibernate.show_sql" value="true"/> <property name="hibernate.hbm2ddl.auto" value="update"/> </properties> </persistence-unit> </persistence>
三、編寫實體類
@Entity @Table(name = "account") public class Account { /** * @Id :聲明主鍵的配置 * @GeneratedValue 配置主鍵的生成策略 * strategy * GenerationType.IDENTITY:自增,mysql * 底層數據庫必須支持自動增加, * GenerationType.SEQUENCE:序列,oracle * 底層數據庫必須支持序列 * GenerationType.TABLE:jpa提供的一種機制,經過一張數據庫表的形式幫助咱們完成主鍵自增 * GenerationType.AUTO:有程序自動的幫助咱們選擇主鍵的生成策略 * * @Column配置屬性和字段的映射關係 */ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private Integer id; @Column(name = "name") private String name; @Column(name = "money") private Double money;
四、測試
@Test public void testSave(){ /** * jpa的操做步驟 * 一、加載配置文件建立工廠對象 * 二、經過工廠得到實體管理器 * 注意:EntityManagerFactory內部維護李不少內容,例如數據庫信息,緩存信息,實體管理器對象,因此建立 * 過程會比較浪費資源。可是具備線程安全的特色,因此能夠再靜態代碼塊中,建立一個公共的EntityManagerFactory * 三、獲取事務對象,開啓事務 * 四、完成增刪改查操做 * persist:保存 * merge:更新 * remove:刪除 * find/getRefrence;根據id查詢 * 五、提交事務 * 六、釋放資源 */ EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJpa"); EntityManager em = factory.createEntityManager(); EntityTransaction tx = em.getTransaction(); tx.begin();; Account account = new Account(); account.setName("李雷"); account.setMoney(2000d); em.persist(account); tx.commit(); em.close(); factory.close(); }
自定義工具類:
public class JpaUtils { private static EntityManagerFactory factory; static { factory=Persistence.createEntityManagerFactory("myJpa"); } public static EntityManager getEntityManager(){ return factory.createEntityManager(); } }
增刪改操做:
/** * 查詢結果當即加載 */ @Test public void testFind(){ EntityManager em = JpaUtils.getEntityManager(); EntityTransaction tx = em.getTransaction(); tx.begin(); Account account = em.find(Account.class, 1); System.out.println(account); tx.commit(); em.close(); } /** * 查詢結果延遲加載 */ @Test public void testReference(){ EntityManager em = JpaUtils.getEntityManager(); EntityTransaction tx = em.getTransaction(); tx.begin(); Account account = em.getReference(Account.class, 1); System.out.println(account); tx.commit(); em.close(); } public void testRemove(){ EntityManager em = JpaUtils.getEntityManager(); EntityTransaction tx = em.getTransaction(); tx.begin(); Account account = em.find(Account.class,1); em.remove(account); tx.commit(); em.close(); } @Test public void testupdate(){ EntityManager em = JpaUtils.getEntityManager(); EntityTransaction tx = em.getTransaction(); tx.begin(); Account account = em.find(Account.class,1); account.setName("李小雷"); em.merge(account); tx.commit(); em.close(); }
jpql查詢:
jpql:特徵與原生sql語句類型,而且徹底面向對象,經過類名和屬性訪問,而不是表名和表的屬性
示例代碼:
public class JpqlTest { /** * 查詢所有 */ @Test public void testFindAll(){ EntityManager em = JpaUtils.getEntityManager(); EntityTransaction transaction = em.getTransaction(); transaction.begin();; String jpql = "from Account"; Query query = em.createQuery(jpql); List resultList = query.getResultList(); for (Object o : resultList){ System.out.println(o); } transaction.commit(); em.close(); } /** * 排序查詢 */ @Test public void testOrders(){ EntityManager em = JpaUtils.getEntityManager(); EntityTransaction transaction = em.getTransaction(); transaction.begin();; String jpql = "from Account order by id desc"; Query query = em.createQuery(jpql); List resultList = query.getResultList(); for (Object o : resultList){ System.out.println(o); } transaction.commit(); em.close(); } /** * 統計查詢 */ @Test public void testCount(){ EntityManager em = JpaUtils.getEntityManager(); EntityTransaction transaction = em.getTransaction(); transaction.begin();; String jpql = "select count(id) from Account"; Query query = em.createQuery(jpql); Object singleResult = query.getSingleResult(); System.out.println(singleResult); transaction.commit(); em.close(); } /** *分頁查詢 */ @Test public void testPaged(){ EntityManager em = JpaUtils.getEntityManager(); EntityTransaction transaction = em.getTransaction(); transaction.begin();; String jpql = "from Account"; Query query = em.createQuery(jpql); List resultList = query.getResultList(); //開始索引 query.setFirstResult(1); //查詢條數 query.setMaxResults(2); for (Object o : resultList){ System.out.println(o); } transaction.commit(); em.close(); } /** * 條件查詢 * */ @Test public void testCondition(){ EntityManager em = JpaUtils.getEntityManager(); EntityTransaction transaction = em.getTransaction(); transaction.begin();; String jpql = "from Account where name like ? "; Query query = em.createQuery(jpql); query.setParameter(1,"李%"); List resultList = query.getResultList(); for (Object o : resultList){ System.out.println(o); } transaction.commit(); em.close(); } }
springDataJpa:
spring基於orm框架jpa規範的基礎上封裝的一套jpa應用框架,可以使開發者極簡的代碼實現對數據庫的訪問和操做,它提供了包括增刪改查等在內的經常使用功能,且易於擴展,學習並使用spring data jpa能夠極大提升開發效率。
入門案例:
一、導入MAVEN座標
<properties> <spring.version>5.0.2.RELEASE</spring.version> <hibernate.version>5.0.7.Final</hibernate.version> <slf4j.version>1.6.6</slf4j.version> <log4j.version>1.2.12</log4j.version> <c3p0.version>0.9.1.2</c3p0.version> <mysql.version>5.1.6</mysql.version> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.6.8</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>4.2.4.RELEASE</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>${hibernate.version}</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>${hibernate.version}</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>5.2.1.Final</version> </dependency> <dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> <version>2.2.11</version> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-core</artifactId> <version>2.2.11</version> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-impl</artifactId> <version>2.2.11</version> </dependency> <dependency> <groupId>javax.activation</groupId> <artifactId>activation</artifactId> <version>1.1.1</version> </dependency> <dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>${c3p0.version}</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>${log4j.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>${slf4j.version}</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-jpa</artifactId> <version>2.1.9.RELEASE</version> </dependency> <dependency> <groupId>javax.el</groupId> <artifactId>javax.el-api</artifactId> <version>2.2.4</version> </dependency> <dependency> <groupId>org.glassfish.web</groupId> <artifactId>javax.el</artifactId> <version>2.2.4</version> </dependency> </dependencies>
二、建立配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/jdbc https://www.springframework.org/schema/jdba/spring-jdbc.xsd http://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/data/jpa https://www.springframework.org/schema/data/jpa/spring-jpa.xsd"> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="packagesToScan" value="lianbang.wu.domain"/> <property name="persistenceProvider" > <bean class="org.hibernate.jpa.HibernatePersistenceProvider"></bean> </property> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="generateDdl" value="false"/> <property name="database" value="MYSQL"/> <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect"/> <property name="showSql" value="true"/> </bean> </property> <property name="jpaDialect" > <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/> </property> <property name="jpaProperties"> <props> <prop key="hibernata.hbm2ddl.auto">update</prop> </props> </property> </bean> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"/> <property name="jdbcUrl" value="jdbc:mysql:///eesy?useUnicode=true&characterEncoding=UTF-8"/> <property name="password" value="120609"/> <property name="user" value="root"/> </bean> <jpa:repositories base-package="lianbang.wu.dao" transaction-manager-ref="transactionManager" entity-manager-factory-ref="entityManagerFactory"></jpa:repositories> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"></property> </bean> <context:component-scan base-package="lianbang.wu"></context:component-scan>
三、建立實體類
@Entity @Table(name = "account") public class Account { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private Integer id; @Column(name = "name") private String name; @Column(name = "money") private Double money;
四、建立Dao接口
public interface AccountDao extends JpaRepository<Account,Integer>, JpaSpecificationExecutor<Account> { }
springDataJpa的運行過程和原理:
一、經過JdkDynamicAopProxy的invoke方法建立了一個動態代理對象
二、SimpleJpaRepository當中封裝了JPA操做(藉助JPA的api完成數據庫的CRUD)
三、經過hibernate完成數據庫操做(封裝了jdbc)
複雜查詢:
一、接口中定義好的方法完成查詢
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:applicationContext.xml") public class AccountTest { @Autowired private AccountDao accountDao; /** * save:保存或者更新 * 若是沒有主鍵屬性,保存 * 若是有主鍵屬性,更新 */ @Test public void testFindOne(){ Account account = new Account(); account.setName("李蕾蕾"); account.setMoney(2000d); accountDao.save(account); } /** * 查詢總數 */ @Test public void testCount(){ long count = accountDao.count(); System.out.println(count); } /** * 查詢是否存在 */ @Test @Transactional public void testGetone(){ Account one = accountDao.getOne(1); System.out.println(one); } @Test public void testJpql(){ Account account = accountDao.findJpql("李小雷"); System.out.println(account); } }
二、jpql查詢
/** * 注意:多個佔位符參數,賦值的時候,默認狀況下,佔位符的位置須要和方法參數中的位置保存一致,能夠指定佔位符參數的位置, * ?+ 索引位置 * * @Modifying:表明執行的方法是更新操做 * @param name * @return */ @Query(value = "from Account where name = ?1") public Account findJpql(String name);
三、sql查詢
/** * 使用sql查詢 * @return */ @Query(value = "select * from account",nativeQuery = true) public List<Object[]> findSql();
四、方法名稱規則查詢,是對jpql查詢更加深刻的一層封裝,咱們只須要安裝springdatajpa提升的方法名稱規則定義方法,不須要在去配置jpql語句,完成查詢
動態查詢:
Spacification:查詢條件,須要自定義咱們本身的Spacification實現類
Predicate toPredicate(Root<T> var1, CriteriaQuery<?> var2, CriteriaBuilder var3);
root:查詢的根對象,查詢的任何屬性均可以從根對象中獲取
CriteriaQuery:頂層查詢對象,通常不用
CriteriaBuilder:查詢的構造器,封裝了不少的查詢條件。
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:applicationContext.xml") public class SpecTest { @Autowired private AccountDao accountDao; /** * 單個對象查詢 */ @Test public void testspec(){ Specification<Account> spec = new Specification<Account>() { public Predicate toPredicate(Root<Account> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) { //獲取比較屬性 Path<Object> id = root.get("id"); //構造查詢條件 //參數1:比較對象,參數2:比較對象的值 Predicate equal = criteriaBuilder.equal(id, 1); return equal; } }; Optional<Account> account =accountDao.findOne(spec); System.out.println(account); } /** * 多個對象的查詢 */ @Test public void testSpec1(){ Specification<Account> spec = new Specification<Account>() { @Override public Predicate toPredicate(Root<Account> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) { Path<Object> id = root.get("id"); Path<Object> name = root.get("name"); final Predicate p1 = criteriaBuilder.equal(id, 1); final Predicate p2 = criteriaBuilder.equal(name, "李小雷"); final Predicate p3 = criteriaBuilder.and(p1, p2); return p3; } }; Optional<Account> account = accountDao.findOne(spec); System.out.println(account); } /** * 模糊查詢 * equal:直接到path對象,而後進行比較便可 * gt,lt,ge,le,like:獲得path,根據peth指定比較參數類型,在去進行比較 */ @Test public void testSpec3(){ Specification<Account> spec = new Specification<Account>() { @Override public Predicate toPredicate(Root<Account> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) { Path<Object> name = root.get("name"); Predicate like = criteriaBuilder.like(name.as(String.class), "李%"); return like; } }; List<Account> all = accountDao.findAll(spec); for (Account account : all){ System.out.println(account); } } /** * 排序查詢 */ @Test public void testSpec4(){ Specification<Account> spec = new Specification<Account>() { @Override public Predicate toPredicate(Root<Account> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) { Path<Object> name = root.get("name"); Predicate like = criteriaBuilder.like(name.as(String.class), "李%"); return like; } }; //參數1:排列順序,參數2:排序屬性名稱 Sort sort = new Sort(Sort.Direction.DESC,"id"); List<Account> all = accountDao.findAll(spec,sort); for (Account account : all){ System.out.println(account); } } /** * 分頁查詢 */ @Test public void testSpec5(){ Specification<Account> spec = new Specification<Account>() { @Override public Predicate toPredicate(Root<Account> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) { Path<Object> name = root.get("name"); Predicate like = criteriaBuilder.like(name.as(String.class), "李%"); return like; } }; //PageRequest對象是Pageable接口的實現類, //參數1:當前查詢的頁數(從0開始),參數2:每頁查詢的數量 Pageable pageable = new PageRequest(0,2); Page<Account> all = accountDao.findAll(spec,pageable); System.out.println(all.getContent());//獲得數據集合列表 System.out.println(all.getTotalElements());//獲得總條數 System.out.println(all.getTotalPages());//獲得總頁數 for (Account account : all){ System.out.println(account); } } }
多表操做
一對多:
實體類關係創建以及映射配置
一、@OneToMany:
做用: 創建一對多的關係映射
屬性:
targetEntityClass:指定多的多方的類的字節碼
mappedBy:指定從表實體類中引用主表對象的名稱。
cascade:指定要使用的級聯操做
fetch:指定是否採用延遲加載
orphanRemoval:是否使用孤兒刪除
二、@ManyToOne
做用: 創建多對一的關係
屬性:
targetEntityClass:指定一的一方實體類字節碼
cascade:指定要使用的級聯操做
fetch:指定是否採用延遲加載
三、@JoinColumn
做用: 用於定義主鍵字段和外鍵字段的對應關係。
屬性:
name:指定外鍵字段的名稱
referencedColumnName:指定引用主表的主鍵字段名稱
unique:是否惟一。默認值不惟一
nullable:是否容許爲空。默認值容許。
insertable:是否容許插入。默認值容許。
updatable:是否容許更新。默認值容許。
columnDefinition:列的定義信息。
五、操做需求:保存一個客戶和2個聯繫人
操做誰,就在誰的持久化類中配置級聯
在@OneToMany 中配置cascade=CascadeType.ALL 級聯全部
在實際開發中,級聯刪除請慎用!
多對多:
實體類關係創建以及映射配置
一、@ManyToMany
做用: 用於映射多對多關係
屬性: cascade:配置級聯操做。
fetch:配置是否採用延遲加載。
二、@JoinTable
做用: 針對中間表的配置
屬性: name:配置中間表的名稱
joinColumns:中間表的外鍵字段關聯當前實體類所對應表的主鍵字段
inverseJoinColumn:中間表的外鍵字段關聯對方表的主鍵字段
三、級聯操做:
操做誰,就在誰的持久化類中配置級聯
在@ManyToMany 中配置cascade=CascadeType.ALL 級聯全部
在實際開發中,級聯刪除請慎用!
多表查詢
對象導航查詢:查詢一個對象的同時,經過此對象查詢它的關聯對象
對象圖導航檢索方式是根據已經加載的對象,導航到他的關聯對象。
對象導航查詢的使用要求是:兩個對象之間必須存在關聯關係。
框架默認在一端 對 多端的數據使用 【延遲加載】
框架默認在多端 對 一端的數據使用 【當即加載】
在實際應用中,內存是很是重要的。