首页 > 其他分享 >2020-6-9-jpa

2020-6-9-jpa

时间:2024-03-22 17:16:02浏览次数:21  
标签:name jpa springframework id 2020 org import public

基本概念、hibernate、SpringDataJpa

基本概念

1JPA

JPA (Java Persistence API)Java持久化API。是一套Sun公司Java官方制定的ORM 方案,是规范,是标准

2ORM

ORM(Object Relational Mapping)对象关系映射。在操作数据库之前,先把数据表与实体类关联起来。然后通过实体类的对象操作(增删改查)数据库表

3hibernate

对象关系映射框架,对JDBC进行轻量级的封装,是一个全自动ORM框架,可自动生成SQL语句,自动执行


hibernate

1依赖


    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.hibernate.version>5.0.7.Final</project.hibernate.version>
    </properties>

    <dependencies>
        <!-- junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <!-- hibernate对jpa的支持包 -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>${project.hibernate.version}</version>
        </dependency>

        <!-- c3p0 -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-c3p0</artifactId>
            <version>${project.hibernate.version}</version>
        </dependency>

        <!-- log日志 -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

        <!-- Mysql and MariaDB -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
    </dependencies>

2配置文件

建立一个文件夹META-INF,放入一个persistence.xml的文件

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
    <!--需要配置persistence-unit节点
    持久化单元:
        name:持久化单元名称
        transaction-type:事务管理的方式
                JTA:分布式事务管理
                RESOURCE_LOCAL:本地事务管理
    -->
<persistence-unit name="mysqljpa" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>

    <properties>
        <!--配置数据库信息-->
        <property name="javax.persistence.jdbc.user" value="root"></property>
        <property name="javax.persistence.jdbc.password" value=""></property>
        <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"></property>
        <property name="javax.persistence.jdbc.url" value="jdbc:mysql:///test2"></property>

        <!--配置jpa实现方(hibernate)的配置信息
            显示sql           :   false|true
            自动创建数据库表    :  hibernate.hbm2ddl.auto
                    create      : 程序运行时创建数据库表(如果有表,先删除表再创建)
                    update      :程序运行时创建表(如果有表,不会创建表)
                    none        :不会创建表
        -->
        <property name="hibernate.show_sql" value="true" />
        <property name="hibernate.hbm2ddl.auto" value="update" />
    </properties>
</persistence-unit>
</persistence>

log4j.properties

# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE            debug   info   warn error fatal
log4j.rootCategory=debug, CONSOLE, LOGFILE

# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE

# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n

# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=d:\axis.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n


3实体类

package entity;

import javax.persistence.*;

@Entity//表示这个类是要建立映射关系的实体类
@Table(name="account")//这个实体类映射的表格
public class Account {
    @Id//主键
    @GeneratedValue(strategy = GenerationType.IDENTITY)//自增
    private int id;

    @Column(name = "name")//映射到表的列
    private String name;

    @Column(name = "money")
    private int money;

    public Account(String name, int money) {
        this.name = name;
        this.money = money;
    }

    public Account() {
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getMoney() {
        return money;
    }

    public void setMoney(int money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", money=" + money +
                '}';
    }
}

@GeneratedValue的strategy

strategy 说明
GenerationType.IDENTITY 数据库机制,底层数据库支持自动增长,mysql
GenerationType.SEQUENCE 数据库机制,底层数据库支持支持序列,oracle
GenerationType.TABLE JPA机制,通过一张数据库表完成自增
GenerationType.AUTO 自动

4增删改查

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import entity.Account;

public class Test {
    static EntityManagerFactory factory;
    static EntityManager entityManager;
    static EntityTransaction transaction;
    static {
        factory= Persistence.createEntityManagerFactory ("mysqljpa");
        entityManager=factory.createEntityManager ();
        transaction=entityManager.getTransaction ();
    }
    @org.junit.Test
    public void add(){//新增

        transaction.begin ();
        Account account=new Account ();
        account.setName ("abc");
        account.setMoney (1000);
        entityManager.persist (account);
        transaction.commit ();
        System.out.println ("-------------------华丽的分割线-----------------------");
        System.out.println (account);//id是插入数据库后返回的id值
        entityManager.close ();
    }
    @org.junit.Test
    public void delete(){//删除
        transaction.begin ();
        Account account=entityManager.find (Account.class,11);
        entityManager.remove (account);
        transaction.commit ();
        entityManager.close ();
    }
    @org.junit.Test
    public void update(){//更新
        transaction.begin ();
        Account account=entityManager.find (Account.class,8);
        account.setMoney (2000);
        entityManager.merge (account);
        transaction.commit ();
        entityManager.close ();
    }
    @org.junit.Test
    public void find(){
        Account account=entityManager.find (Account.class,1);
        Account account1=entityManager.getReference (Account.class,3);//懒加载方式查询
        System.out.println (account);
        System.out.println (account1);//不执行这一句,将不会执行sql
        entityManager.close ();
    }
}

find和getReference区别

(1)前者返回的是传入类的对象,后者返回的是传入类的代理对象

(2)前者立即执行sql,后者在使用返回对象时执行sql

5JPQL

一种操作实体类的的语句,类似SQL。jpql与SQL的区别就是SQL是面向对象关系数据库,他操作的是数据表和数据列,而jpql操作的对象是实体对象和实体属性

封装一个获取EntityManager的工具

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class jpaUtils {
    static EntityManagerFactory factory;
    static EntityManager entityManager;
    static {
        factory= Persistence.createEntityManagerFactory ("mysqljpa");
        entityManager=factory.createEntityManager ();
    }
    public static EntityManager getEntityManager(){
        return entityManager;
    }

}

详细

import org.junit.Test;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.util.List;

public class jpql {
    @Test
    public void findall(){//查询全部
        EntityManager entityManager=jpaUtils.getEntityManager ();

        String jpql="from entity.Account";//相当于SELECT * FROM account

        Query query=entityManager.createQuery (jpql);
        List list=query.getResultList ();
        System.out.println (list);
    }
    @Test
    public void findallDest(){//排序查询
        EntityManager entityManager=jpaUtils.getEntityManager ();

        String jpql="from entity.Account order by id desc ";//相当于SELECT * FROM account ORDER BY id DESC

        Query query=entityManager.createQuery (jpql);
        List list=query.getResultList ();
        System.out.println (list);
    }
    @Test
    public void findallCount(){//统计查询
        EntityManager entityManager=jpaUtils.getEntityManager ();

        String jpql="select count(id) from entity.Account";//相当于SELECT COUNT(id) FROM account

        Query query=entityManager.createQuery (jpql);
        List list=query.getResultList ();
        System.out.println (list);
    }
    @Test
    public void findallLimit(){//分页查询
        EntityManager entityManager=jpaUtils.getEntityManager ();

        String jpql="from entity.Account";
        Query query=entityManager.createQuery (jpql);
        query.setFirstResult (0);
        query.setMaxResults (5);
        //相当于SELECT * FROM account LIMIT 0,5

        List list=query.getResultList ();
        System.out.println (list);
    }
    @Test
    public void findallWhere(){//条件查询
        EntityManager entityManager=jpaUtils.getEntityManager ();

        String jpql="from entity.Account where name like ?";
        Query query=entityManager.createQuery (jpql);
        query.setParameter (1,"%S%");
        //相当于SELECT * FROM account WHERE name like '%S%'

        List list=query.getResultList ();
        System.out.println (list);
    }
}


SpringDataJpa

是 spring data 项目下的一个模块。提供了一套基于 JPA标准操作数据库的简化方案。底层默认的是依赖 Hibernate JPA 来实现的

1依赖

	<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>
        <!-- junit单元测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <!-- spring beg -->
        <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>

        <!-- spring对orm框架的支持包-->
        <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>

        <!-- spring end -->

        <!-- hibernate beg -->
        <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>
        <!-- hibernate end -->

        <!-- c3p0 beg -->
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>${c3p0.version}</version>
        </dependency>
        <!-- c3p0 end -->

        <!-- log end -->
        <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>
        <!-- log end -->


        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>

        <!-- spring data jpa 的坐标-->
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-jpa</artifactId>
            <version>1.9.0.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- el beg 使用spring data jpa 必须引入 -->
        <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>
        <!-- el end -->
    </dependencies>

2配置文件

<?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:aop="http://www.springframework.org/schema/aop"
       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: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/aop http://www.springframework.org/schema/aop/spring-aop.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
		http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
		http://www.springframework.org/schema/data/jpa
		http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

    <!--spring 和 spring data jpa的配置-->

    <!-- 1.创建entityManagerFactory对象交给spring容器管理-->
    <bean id="entityManagerFactoty" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <!--配置的扫描的包(实体类所在的包) -->
        <property name="packagesToScan" value="entity" />
        <!-- jpa的实现厂家 -->
        <property name="persistenceProvider">
            <bean class="org.hibernate.jpa.HibernatePersistenceProvider"/>
        </property>

        <!--jpa的供应商适配器 -->
        <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" />
                <!--是否显示sql -->
                <property name="showSql" value="true" />
            </bean>
        </property>

        <!--jpa的方言 :高级的特性 -->
        <property name="jpaDialect" >
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
        </property>
        
        <!--jpa实现方式的配置信息-->
        <property name="jpaProperties">
            <props>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
            </props>
        </property>

    </bean>

    <!--2.创建数据库连接池 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="root"></property>
        <property name="password" value=""></property>
        <property name="jdbcUrl" value="jdbc:mysql:///test2?serverTimezone=UTC&amp;useUnicode=true&amp;characterEncoding=UTF-8" ></property>
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
    </bean>

    <!--3.整合spring dataJpa-->
    <jpa:repositories base-package="dao" transaction-manager-ref="transactionManager"
                      entity-manager-factory-ref="entityManagerFactoty" ></jpa:repositories>

    <!--4.配置事务管理器 -->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactoty"></property>
    </bean>

    <!-- 4.txAdvice-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="save*" propagation="REQUIRED"/>
            <tx:method name="insert*" propagation="REQUIRED"/>
            <tx:method name="update*" propagation="REQUIRED"/>
            <tx:method name="delete*" propagation="REQUIRED"/>
            <tx:method name="get*" read-only="true"/>
            <tx:method name="find*" read-only="true"/>
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

    <!-- 5.aop-->
    <aop:config>
        <aop:pointcut id="pointcut" expression="execution(* service.*.*(..))" />
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut" />
    </aop:config>


    <!--5.声明式事务 -->

    <!-- 6. 配置包扫描-->
    <context:component-scan base-package="java" ></context:component-scan>
</beans>

3实体类

package entity;

import javax.persistence.*;

@Entity
@Table(name = "account")
public class Account {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "name")
    private String name;

    @Column(name = "money")
    private int money;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getMooney() {
        return money;
    }

    public void setMooney(int mooney) {
        this.money = mooney;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", mooney=" + money +
                '}';
    }
}

1)jpa通过实体类创建的表引擎时MYSIAM,如果两张相关联的表引擎不同,在项目启动时会报错

2)如果出现org.springframework.orm.hibernate3.HibernateSystemException: Null value was assigned to a property这个错误,在实体类中将报错字段的类型设置为其包装类可解决

4dao

package dao;

import entity.Account;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;

public interface AccountDao extends JpaRepository<Account,Long>, JpaSpecificationExecutor<Account> {//继承2个接口,将实体类传入
}

5普通增删改查

import dao.AccountDao;
import entity.Account;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@RunWith (SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:ApplicationContex.xml")
public class test {
    @Autowired
    private AccountDao accountDao;

    @Test
    public void findAll(){//查询所有
        List list=accountDao.findAll ();
        System.out.println (list);
    }
    @Test
    public void findOne(){//查询一条记录
        Account account=accountDao.findOne (5L);
        System.out.println (account);
    }
    @Test
    public void delete(){//删除一条记录
        accountDao.delete (6L);
    }
    @Test
    public void update(){//修改一条记录
        Account account=accountDao.findOne (5L);
        account.setName ("sylvester");
        accountDao.save (account);
    }
    @Test
    public void insert(){//插入一条记录
        Account account=new Account ();
        account.setName ("abcde");
        account.setMooney (1000);
        accountDao.save (account);
    }
    @Test
    public void count(){//查询总数
        long count=accountDao.count ();
        System.out.println (count);
    }
    @Test
    public void exist(){//查询某条记录是否存在
        boolean exists=accountDao.exists (5L);
        System.out.println (exists);
    }
    @Test
    @Transactional
    public void getOne(){//查询一条记录,延迟加载,必须加上@Transactional
        Account account=accountDao.getOne (5L);
        System.out.println (account);
    }
}

6JPQL查询

1步骤

1)dao接口中定义方法

2)在方法上加@Query注解,并将jpql语句写在里面

2详细

1)AccountDao

package dao;

import entity.Account;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;

import java.util.List;

public interface AccountDao extends JpaRepository<Account,Long>, JpaSpecificationExecutor<Account> {
    @Query(value = "from entity.Account where name=?1")
    List<Account> findByName(String name);

    @Query(value = "from entity.Account where name=?1 and id=?2")
    Account findByNameAndId(String name,Long id);

    @Query(value = "update entity.Account set name=?1 where id=?2")
    @Modifying//表明改操作是更新操作
    void updateAccount(String name,long id);

    //原生sql
    @Query(nativeQuery =true,value = "select * from account")
    List<Object[]> findAllAcount();
}


注意

如果时更新方法,要在方法上加@Modifying

2)测试代码

import dao.AccountDao;
import entity.Account;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:ApplicationContex.xml")
public class test1 {

    @Autowired
    AccountDao accountDao;

    @Test
    public void findbyname(){//按照姓名查找
        List<Account>  accounts=accountDao.findByName ("abc");
        System.out.println (accounts);
    }
    @Test
    public void findbynameandid(){//按照姓名和id查找
        Account account=accountDao.findByNameAndId ("sylvester",5L);
        System.out.println (account);
    }
    @Test
    @Transactional//开启事务
    @Rollback(false)//关闭回滚
    public void updateaccount(){//更新
        accountDao.updateAccount ("sylvester1",5);
    }
	//更新操作一定要加上事务,否则报错
    
    @Test
    public void nativefindall(){//原生sql查找
        List<Object[]> list=accountDao.findAllAcount ();
        for (Object[] row:
             list) {
            System.out.println (Arrays.toString (row ));
        }
    }
}

7方法命名规则查询

spring对JPQL更深一层的封装,只需按方法规则定义方法,无需配JPQL语句

1)AccountDao

package dao;

import entity.Account;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;

import java.util.List;

public interface AccountDao extends JpaRepository<Account,Long>, JpaSpecificationExecutor<Account> {
    List<Account> findByName(String name);
    List<Account> findByNameLike(String name);
    List<Account> findByNameLikeAndMoney(String name,int money);
}

2)测试代码

import dao.AccountDao;
import entity.Account;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.List;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:ApplicationContex.xml")
public class test2 {

    @Autowired
    AccountDao accountDao;

    @Test
    public void test_findbyname(){//按姓名查找
        List<Account> accounts=accountDao.findByName("sylvester1");
        System.out.println (accounts);
    }
    @Test
    public void test_findbynamelike(){//模糊查询
        List<Account> accounts=accountDao.findByNameLike("%s%");
        System.out.println (accounts);
    }
    @Test
    public void test_findbynamelikeandmoney(){//多条件查询
        List<Account> accounts=accountDao.findByNameLikeAndMoney("%s%",1000);
        System.out.println (accounts);
    }
}

3)查找外键字段

package com.example.sub_for_dep.responsitory;

import com.example.sub_for_dep.entity.Subject;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;


public interface SubjectResponsitory extends JpaRepository<Subject,Long> {
    @Query("from Subject as s where s.subject_type_id=:subject_type_id")
    Page<Subject> findAllBySubject_type_id(@Param ("subject_type_id") long subject_type_id, Pageable pg);
}

subject_type_id是一个外键的字段,只能使用jpql查询,否则报错

8specifications动态查询

创建一个Specification对象,在对象里定义查询规则,再将该对象传入查询方法中

import dao.AccountDao;
import entity.Account;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.persistence.criteria.*;
import java.util.List;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:ApplicationContex.xml")
public class test3 {

    @Autowired
    AccountDao accountDao;

    @Test
    public void findbyname(){//按名字查询
        Specification<Account> spc=new Specification<Account> ( ) {
            public Predicate toPredicate(Root<Account> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Path<Object> name=root.get("name");//选择列
                Predicate predicate=criteriaBuilder.equal (name,"sylvester");//设置查询条件name=sylvester
                return predicate;
            }
        };
        List<Account> accounts=accountDao.findAll (spc);
        System.out.println (accounts);
    }
    @Test
    public void findbynameandmoney(){//多条件查询
        Specification<Account> spc=new Specification<Account> ( ) {
            public Predicate toPredicate(Root<Account> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Path<Object> name=root.get("name");
                Path<Object> money=root.get("money");
                Predicate p1=criteriaBuilder.equal (name,"sylvester");
                Predicate p2=criteriaBuilder.equal (money,1000);
                Predicate and=criteriaBuilder.and (p1,p2);
                return and;
            }
        };
        List<Account> accounts=accountDao.findAll (spc);
        System.out.println (accounts);
    }
    @Test
    public void findbynamelike(){//模糊查询
        Specification<Account> spc=new Specification<Account> ( ) {
            public Predicate toPredicate(Root<Account> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Path<Object> name=root.get("name");
                Path<Object> money=root.get("money");
                Predicate predicate=criteriaBuilder.like (name.as(String.class),"%s%");
                //注意gt,lt,ge,le,like需指定比较参数类型
                return predicate;
            }
        };
        List<Account> accounts=accountDao.findAll (spc);
        System.out.println (accounts);
    }
    @Test
    public void findallsorted(){//倒序查询
        Sort sort=new Sort (Sort.Direction.DESC,"id");//按id倒序排列
        List<Account> accounts=accountDao.findAll (sort);
        System.out.println (accounts);
    }
    @Test
    public void findallpage(){//分页查询
        Pageable pageable=new PageRequest (1,5);//第一个参数是当前页数,第二个参数是每页数据数量
        Page<Account> page=accountDao.findAll (pageable);
        System.out.println (page.getContent ());//获取当前页的所有数据
        System.out.println (page.getTotalElements ());//获取当前有多少数据
        System.out.println (page.getTotalPages ());//获取当前有多少页
    }
    @Test
    public void countall(){//查询在某个条件下有多少数据
        Specification<Account> spc=new Specification<Account> ( ) {
            public Predicate toPredicate(Root<Account> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Path<Object> name=root.get("name");
                Predicate predicate=criteriaBuilder.equal (name,"sylvester");
                return predicate;
            }
        };
        long num=accountDao.count(spc);
        System.out.println (num);
    }
}

9一对多表

对于表之间一对多的关系,只需要在实体类中配置即可

如:书和出版社的关系:1本书对应1个出版社,1个出版社对应多本书

1)实体类Book

package entity;

import javax.persistence.*;

@Entity
@Table(name = "book")
public class Book {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "book_id")
    private long book_id;

    @Column(name = "name")
    private String name;
	
    @Column(name ="publisher_id")
    private long publisher_id;
    
    @ManyToOne(targetEntity = Publisher.class,fetch = FetchType.LAZY)//targetEntity指向相关联的另一张表
    @JoinColumn(name = "book_pub_id",referencedColumnName = "publisher_id",insertable = false,updatable = false)//name为book表的外键名,referencedColumnName指向publisher表的主键;两个实体映射到同一张表或者有两个属性(一个是一般属性,一个是多对一的属性)映射到数据库的同一列,就会报错,需要关闭掉该字段的插入、更新操作,如insertable = false, updatable = false
    private Publisher publisher;
    public long getBook_id() {
        return book_id;
    }

    public void setBook_id(long book_id) {
        this.book_id = book_id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Publisher getPublisher() {
        return publisher;
    }

    public void setPublisher(Publisher publisher) {
        this.publisher = publisher;
    }
    
    public void getPublisher_id() {
        return publisher_id;
    }
    
    public void setPublisher_id(long publisher_id) {
        this.publisher_id = publisher_id;
    }

    @Override
    public String toString() {
        return "Book{" +
                "book_id=" + book_id +
                ", name='" + name + '\'' +
                ", pblisher=" + publisher +
                '}';
    }
}

2)实体类Publisher

package entity;

import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;


@Entity
@Table(name="publisher")
public class Publisher {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "publisher_id")
    private long publisher_id;

    @Column(name = "name")
    private String name;

    /*
     * cascade : 配置级联(可以配置到设置多表的映射关系的注解上)
     *      CascadeType.all         : 所有
     *                  MERGE       :更新
     *                  PERSIST     :保存
     *                  REMOVE      :删除
     *  注意:开发中尽量不使用级联
     */
    @OneToMany(mappedBy = "publisher")//放弃维护权,mappedBy为对方表配置的关系属性名称,cascade表示配置级联
    private Set<Book> books=new HashSet<Book> ();
    //注意:放弃维护调用getBooks().add()无效

    public long getPublisher_id() {
        return publisher_id;
    }

    public void setPublisher_id(long publisher_id) {
        this.publisher_id = publisher_id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Set<Book> getBooks() {
        return books;
    }

    public void setBooks(Set<Book> books) {
        this.books = books;
    }

    @Override
    public String toString() {
        return "Publisher{" +
                "publisher_id=" + publisher_id +
                ", name='" + name + '\'' +
                ", books=" + books +
                '}';
    }
}

3)测试

import dao.BookDao;
import dao.PublisherDao;
import entity.Book;
import entity.Publisher;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:ApplicationContex.xml")
public class test4 {
    @Autowired
    BookDao bookDao;

    @Autowired
    PublisherDao publisherDao;

    @Test
    @Transactional
    @Rollback(false)
    public void test(){//两张表各创建一条记录,并产生关联
        Publisher publisher=new Publisher ();
        publisher.setName ("人民出版社");

        Book book=new Book ();
        book.setName ("西游记");

        book.setPublisher (publisher);
        bookDao.save (book);
        publisherDao.save (publisher);
    }
    @Test
    @Transactional
    @Rollback(false)
    public void addOne(){//新增一本书,归属到id为1的出版社
        Book book=new Book ();
        book.setName ("白鹿原");
        Publisher publisher=publisherDao.findOne (1L);
        book.setPublisher (publisher);
        bookDao.save (book);
    }
}

10多对多表

如:1一个用户可对应多个角色,1个角色可对应多个用户

1)角色表role

package entity;

import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;

@Entity
@Table(name = "role")
public class Role {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "role_id")
    private long id;

    @Column(name = "name")
    private String name;

    /*
    可放弃维护,可设置级联,与一对多类似,但一般情况下不放弃维护
     */
    @ManyToMany(targetEntity = User.class)
    @JoinTable(name="user_role",joinColumns = {//name为第三张表的表名
            @JoinColumn(name="role_id",referencedColumnName = "role_id")//设置当前表在第三张表的外键,name为外键名,referencedColumnName指向当前表的id
    },inverseJoinColumns = {
            @JoinColumn(name="user_id",referencedColumnName = "user_id")//设置对方表在第三张表的外键
    })
    private Set<User> roles=new HashSet<User> ();

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Set<User> getRoles() {
        return roles;
    }

    public void setRoles(Set<User> roles) {
        this.roles = roles;
    }

    @Override
    public String toString() {
        return "Role{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", roles=" + roles +
                '}';
    }
}

2)用户表user

package entity;

import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;

@Entity
@Table(name = "user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "user_id")
    private long id;

    @Column(name = "name")
    private String name;

    @ManyToMany(targetEntity = Role.class)
    @JoinTable(name="user_role",joinColumns = {
            @JoinColumn(name="user_id",referencedColumnName = "user_id")
    },inverseJoinColumns = {
            @JoinColumn(name="role_id",referencedColumnName = "role_id")
    })
    private Set<Role> roles=new HashSet<Role> ();

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Set<Role> getRoles() {
        return roles;
    }

    public void setRoles(Set<Role> roles) {
        this.roles = roles;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", roles=" + roles +
                '}';
    }
}

3)测试

import dao.RoleDao;
import dao.UserDao;
import entity.Role;
import entity.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:ApplicationContex.xml")
public class test5 {
    @Autowired
    RoleDao roleDao;

    @Autowired
    UserDao userDao;

    @Test
    @Transactional
    @Rollback(false)
    public void test(){//建立一个用户和一个角色,并产生联系
        Role role=new Role ();
        role.setName ("管理员");

        User user=new User ();
        user.setName ("user1");

        user.getRoles ().add (role);
        roleDao.save (role);
        userDao.save (user);
    }
}

注意

在多对多表的实体类中,如果双方都定义了外键及包含外键的toString方法,在打印其中一个实体对象时,两个相关联的实体会调用对方的toString方法从而进入死循环导致栈溢出

11对象导航查询

查询某个对象时,可通过该对象查询到与之相关联的其他对象

	//核心代码
	@Test
    @Transactional//解决no session问题
    public void test1(){
        Role role=roleDao.findOne (1L);
        Set<User> users=role.getUsers ();
        for (User user:
             users) {
            System.out.println (user.getId ());
            System.out.println (user.getName ());
        }
    }

一对多关系中:

一方查多方,延迟加载

多方查一方,立即加载

常见问题

1使用JPQL进行更新、删除操作报错

Executing an update/delete query; nested exception is javax.persistence.TransactionRequiredException: Executing an update/delete query

在jpa中所有更新、删除操作要求必须是在事务的前提下进行操作,所以要在持久化接口中@Transactional标注事务

package com.example.gradle_springboot.mapper;

import com.example.gradle_springboot.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;

import javax.transaction.Transactional;
import java.util.List;

@Transactional//标注事务
public interface UserMapper extends JpaRepository<User,Integer>, JpaSpecificationExecutor<User> {
    @Modifying
    @Query(value = "update User set deleted=1 where id=?1")
    void logicDeleteById(Integer id);

    @Query(value = "from User where deleted=0")
    List<User> findByIdNotDeleted();
}

2查询数据报错

org.hibernate.LazyInitializationException: could not initialize proxy [com.example.gradle_springboot.entity.User#1] - no Session

网上很多解决方案,多是简单粗暴地在配置文件中将全局懒加载关掉。但这样的做法并不好,应该是在出问题的实体类上将该实体类的懒加载关掉,在出问题的实体类上加@Proxy(lazy = false)注解

3逻辑删除的实现

jpa中没有实现对逻辑删除的封装,需要手动去持久化接口中定义删除和查询方法

4乐观锁的实现

在实体类定义一个属性version并在该属性上新增@Version注解

package com.example.gradle_springboot.entity;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
import org.hibernate.annotations.Proxy;

import javax.persistence.*;

@Entity
@Table(name="user")
@JsonIgnoreProperties(value = { "hibernateLazyInitializer", "handler" })
@Data
@Proxy(lazy = false)
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private String username;

    private String password;

    @Version
    private Integer version=0;

    //逻辑删除
    private Integer deleted=0;
}

在进行每更新操作时会自增版本号

5对save方法的理解

1)对于传入的实体类,如果有id,该操作为更新操作,否则为插入操作

2)当进行更新操作时,如果实体类并没有被修改,执行save方法时是不会去操作数据的

6自动填充时间

1)在启动类上添加@EnableJpaAuditing,启动

2)在实体类添加@EntityListeners(AuditingEntityListener.class)

3)在字段上添加@CreatedDate,@LastModifiedDate

7分页查询取不到数据问题

//省略部分代码
Pageable pageable=PageRequest.of(1,10);//第一页,每页10条数据(第一个参数应该是0)
Page<Subject> subjectPage=subjectResponsitory.findAll(pageable);
List<Subject> subjects=subjectPage.getContent();//取出的数据size为0,也就是没有取到数据

查看PageRequest的静态方法of的源码

	//部分
	/**
	 * Creates a new unsorted {@link PageRequest}.
	 *
	 * @param page zero-based page index, must not be negative. page参数从0开始
	 * @param size the size of the page to be returned, must be greater than 0.
	 * @since 2.0
	 */
	public static PageRequest of(int page, int size) {
		return of(page, size, Sort.unsorted());
	}

从源码上看,第一页时page应该为0,所以上面取不到数据的原因是:总共只有1页的数据,却取了第二页的数据

8getOne()报错

package com.zhanghuan.scheduler;

import com.zhanghuan.scheduler.job.dao.ScheduleJobDao;
import com.zhanghuan.scheduler.job.dao.ScheduleJobLogDao;
import com.zhanghuan.scheduler.job.entity.ScheduleJobEntity;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;


@SpringBootTest
class SchedulerApplicationTests {

    @Autowired
    ScheduleJobDao scheduleJobDao;
    
    @Test
    void contextLoads() {
        ScheduleJobEntity scheduleJobEntity = scheduleJobDao.getOne("2");//这一行报错
        System.out.println(scheduleJobEntity);
    }

}

如下错误

org.hibernate.LazyInitializationException: could not initialize proxy [com.zhanghuan.scheduler.job.entity.ScheduleJobEntity#2] - no Session

解决方法

package com.zhanghuan.scheduler;

import com.zhanghuan.scheduler.job.dao.ScheduleJobDao;
import com.zhanghuan.scheduler.job.dao.ScheduleJobLogDao;
import com.zhanghuan.scheduler.job.entity.ScheduleJobEntity;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;


@SpringBootTest
class SchedulerApplicationTests {

    @Autowired
    ScheduleJobLogDao scheduleJobLogDao;

    @Autowired
    ScheduleJobDao scheduleJobDao;
    @Test
    void contextLoads() {
        //使用findById替换
        ScheduleJobEntity scheduleJobEntity = scheduleJobDao.findById("2").get();
        System.out.println(scheduleJobEntity);
    }

}

9数据库中数据时间不正确

代码中将new Date()存入数据库,查看数据发现时间不正确,此问题是数据源中的url未配置正确导致,应配置为jdbc:mysql:///scheduler?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8

标签:name,jpa,springframework,id,2020,org,import,public
From: https://www.cnblogs.com/sylvesterzhang/p/18089856

相关文章

  • 2020-6-30-Docker
    基础概念、安装与卸载、命令、部署、可视化portainer、自制镜像、容器的卷技术、DockerFile、Docker网络、Springboot镜像、Compose基础概念1虚拟技术和容器技术对比虚拟技术容器技术原理虚拟出硬件,运行一个完整的操作系统容器应用直接运行在宿主机,无内核,相互隔离......
  • 2020-6-22-MySQL高级
    数据库引擎对比、索引、SQL语句的性能分析、优化、其他数据库引擎对比MyISAMInnoDB外键不支持支持事务不支持支持行表锁表锁行锁缓存只缓存索引索引、数据都缓存表空间小大关注点性能事务索引1索引分类单值索引:一个索引只包含单个......
  • 2020-6-17-elementui
    安裝、Button组件、文字链接组件、Layout栅格布局、Container容器、Radio组件、CheckBox组件、Input组件、Select选择器、Switch组件、时间日期组件、Upload组件、Form表单、消息提示、表格安裝1安装到项目中在初始化好Vue项目后执行以下命令npmielement-ui-s也可以通过......
  • 2020-7-2-Mybatis-Plus
    依赖、项目内配置、主键生成策略、自动填充时间、乐观锁实现方式、一般查询、分页查询、删除、执行SQL分析打印、条件构造器、代码生成器依赖<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId>......
  • 2020-8-5-tomcat优化
    tomcat安装与配置、优化内容、JMeter、JVM字节码tomcat安装与配置官网下载后上传到服务器$tar-xvfapache-tomcat-8.5.57.tar.gz1)修改用户$viconf/tomcat-users.xml<rolerolename="manager"/><rolerolename="manager-gui"/><rolerolename="admin......
  • 2020-7-28-并发编程
    概述、生产者消费者模型、锁对象、集合的线程安全问题、Callable的使用、计数器、队列、线程池、ForkJoin、异步回调、单例模式、CAS、锁概述1多线程下变量访问存在问题变量访问不可见性2JMM特点所有共享变量存于主内存中每个线程有自己的工作内存线程对变量的操作都必须在......
  • 2020-8-9-JAVA机考题
    二叉排序数及中序遍历实现,socket应用,日志模拟的实现试题一/***实现要求:*1、根据已有的代码片段,实现一个二叉排序树;*2、用中序遍历输出排序结果,结果形如:0,1,2,3,4,5,6,7,8,9,*3、注意编写代码注释*/publicclassBinaryTree{ publicstaticvoidmain(String[]a......
  • 2020-8-6-JVM虚拟机
    运行时数据区域、溢出、垃圾收集、问题解决运行时数据区域Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域1)程序计数器(1)一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器(2)字节码解释器工作时就是通过改变这个计数器的......
  • 2020-8-12-Spring-Security
    资源访问控制方式、认证流程、授权流程、快速开始、授权案例、自定义登陆登出页面、会话管理、基于方法的授权资源访问控制方式基于角色的访问控制Role-BasedAccessControl基于资源的访问控制(常用)Resource-BasedAccessControl认证流程UsernamePasswordAuthenticatio......
  • 2020-2-11-Angular
    Amgular安装、插件安装、新建组件、组件编写、双向绑定、服务、ViewChild、组件间通信、声明周期函数、异步编程、路由、模块化实现懒加载安装npminstall-g@angular/cli查看版本ngv创建项目//在filedir中创建项目,并安装依赖ngnewfiledir//在filedir中创建项目,......