2023年JPA学习笔记.docx
目录目录1一、JPA基础21.1JPA基础21.2JPA开发过程31.3 实体的生命周期及实体管理器常用方法4二、环境搭建52.1 添加JPA支持62.2 添加配置文献62.3测试配置62.4 环境搭建附表6三、常用注解123.1 批注完全参考123.2 ID相关的123.3主键生成策略133.4字段、添加字段、添加表关联133.5映射相关143.6其他14四、JPA映射144.1一对一映射154.1.1共享主键映射154.1.2关联外键映射174.1.3添加表关联174.2一对多关联184.2.1添加字段的一对多、多对一关联184.2.2添加表的一对多、多对一关联194.3多对多关联204.4继承映射21五、JPQL21六、常见异常22一、JPA基础1.1JPA基础JPA:java persistence api支持XML、JDK5.0注解俩种元数据的形式,是SUN公司引入的JPA ORM规范元数据:对象和表之间的映射关系实体:entity,需要使用Javax.persistence.Entity注解或xml映射,需要无参构造函数,类和相关字段不能使用final关键字游离状态实体以值方式进行传递,需要serializableJPA是一套规范、有很多框架支持(如Hibernate3.2以上、Toplink,一般用Hibernate就行 oracle可以用toplink)JPQL1、与数据库无关的,基于实体的查询语言2、操作的是抽象持久化模型3、JPQL是一种强类型语言,一个JPQL语句中每个表达式都有类型4、EJBQL的扩展5、支持projection(可以查询某个实体的字段而不需要查询整个实体)、批量操作(update、delete)、子查询、join、group by having(group by聚合后 having 聚合函数 比较 条件)弱类型语言:没有明显的类型、根据情况变化、容易犯错强类型语言:没个变量都有固定的类型。不容易犯错虽然JPA规范中明确表达无法访问一个集合关系字段抽象模型类型:JPQL规范将一个实体(属性)中所饮食的各种类型称为抽象模型类型状态字段关联字段查询多个字段查出来的是个对象值数组1.2JPA开发过程JPA配置文献声明持久化单元->配置文献persistence.xml编写带标注的实体类编写Dao类xml配置事务类型分为:RESOURCE_LOCAL本地事务、JTA(java事务API)注解Entity将JavaBean标注为一个实体 name属性Table数据库中的表,name名称、catalog数据库名Secondary Table/Secondary Tables多个表Id定义了实体的主键信息GeneratedValue逐渐省城策略GeneratedValue(Strategy = GenerationType.SEQUENCE)SequenceGenerator(name="SEQ_TEST",sequenceName="User_SEQ",allocationSize=25)column属性、字段相应的表字段Temporal属性是时间类型的话可以细分DATEjava.sql.DateTIMEjava.sql.TimeTIMESTAMPjava.sql.TimestampLob标注CLOB、BLOBBase 是否延迟加载Base(fetch = FETCHTYPE.LAZY/FETCHTYPE.EAGER)Transient实体bean中,所有非static、非transient状态变量、字段都要被持久化假如有字段、变量在数据库中没有相应,标注为transient就可以不被持久化标注方式:标注在字段上标注在变量上实体类写法:1、必须有无参的构造函数2、没有final类型的变量或方法3、不可以是public类型的,只能通过get、set方法读写管理实体PersistenceEntityManagerFactoryEntityManagerPersistence.createEntityManagerFactory('persistence.xml中配置的persistence unit').createEntityManager()获取EntityManager1.3 实体的生命周期及实体管理器常用方法EntityManager声明周期Java对象实体管理器数据库1、新实体(new)存在不存在不存在2、持久化实体(managed)存在存在存在3、分离的实体(detached)不存在不存在存在4、删除的实体(removed)存在存在不存在newpersist()find()commit()、clear()DB managed detachedmerge()remove()removed常用方法1、persist(Object)持久化2、remove(Object)删除对象3、find(Class entityClass,Object key)根据主键查询4、flush()实体与底层同步,执行sql5、createQuery()创建JPQL查询对象5、createNativeQuery()根据普通SQL查询5、createNamedQuery()命名查询NamedQuerie标注5、merge(Object)将一个detached的实体持久化到EntityManager中5、close()关闭管理器javax.persistence.Queryint executeUpdate()执行更新、删除、添加Object getSingleResult()执行查询(返回一条记录)List getResultList()执行查询(返回结果链表)Query setParameter(int position,object value)给Query对象设立参数Query setMaxResults(int maxResult)给Query对象设立返回数Query setFirstResult(int firstResult)给Query对象设立返回偏移参数查询(只能用一种)命名参数查询"select u from User where id = :uid"setParameter("uid",value);位置参数查询-Person person = em.find(Person.class,1); /相称于Hibernate的getPerson person = em.getReference(Person.class,1);/相称于Hibernate的load返回一个代理对象/注意延迟加载时的 事务没关闭的时候才好用find 假如找不到返回的是个null,这时候下面在调用null的方法报nullpoint异常reference相称于延迟加载 假如找不到,会在第一次使用就报EntityNotFound异常回调函数(相称于拦截器,下面的方法执行前后调用指定的方法)PrepersistPostPersistPreRemovePostRemovePreUpdatePostUpdatePostLoad载入实体时(find、查询、refresh)-二、环境搭建2.1 添加JPA支持1、准备JPA用到的jar包(JPA支持包)2、window preferences Java BuildPath User Librariesnew User LibraryAdd Jars3、项目 右键 properties(alt+Enter) Java Build Path Libraries Add Library User Library 自己定义的JPA支持包2.2 添加配置文献1、项目中SRC目录下添加META-INF目录(与Web项目下META-INF同名)2、在新添加的META-INF中添加配置文献persistences.xmlpersistence.xml配置信息 (Hibernate)数据库连接信息查询重要配置信息:事务类型:本地事务、JTA事务JPA供应商数据库驱动、URL、User、Password3、在SRC目录下添加log4j.properties文献(显示数据库操作信息的)2.3测试配置1、MySQL测试数据库 2、实体注解3、JUNIT测试方法2.4 环境搭建附表persistence.xml配置信息<?xml version="1.0" encoding="UTF-8"?><persistence version="1.0" xmlns="" xmlns:xsi="" xsi:schemaLocation=":/<!- name="持久化单元命名" transaction-type="本地事务/JTA" -><persistence-unit name="JPA" transaction-type="RESOURCE_LOCAL"><!- 供应商 -><provider>org.hibernate.ejb.HibernatePersistence</provider><properties><!- 参数:数据库驱动名、地址、用户、密码、方言、显示执行SQL语句 -><property name="hibernate.connection.driver_class" value=""/><property name="hibernate.connection.driver_class" value="org.gjt.mm.mysql.Driver"/><property name="hibernate.connection.url" value="jdbc:mysql:/127.0.0.1:3306/JPA"/><property name="hibernate.connection.username" value="root"/><property name="hibernate.connection.password" value="123456"/><property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/><property name="hibernate.show_sql" value="true"/><!- 其他设立 -><property name="minPoolSize" value="5"/><property name="initialPoolSize" value="10"/><property name="idleConnectionTestPeriod" value="120"/><property name="acquireIncrement" value="10"/><property name="checkoutTimeout" value="3600"/><property name="numHelperThreads" value="4"/><property name="maxStatements" value="400"/><property name="maxStatementsPerConnection" value="20"/><property name="maxIdleTime" value="180"/><property name="acquireRetryAttempts" value="30"/><property name="maxPoolSize" value="200"/></properties></persistence-unit></persistence>自动创建|更新|验证数据库表结构。假如不是此方面的需求建议set value="none"。容易导致数据丢失,一般在测试的时候才用<property name="hibernate.hbm2ddl.auto" value="create"></property>、validate 验证数据库表结构create每次加载Hibernate都会删除上一次的表结构,根据model重新生成create-drop每次加载创建,sessionFactory关闭表就自动删除update加载Hibernate就更想你表结构环境测试代码实体注解EntityTable(name="Person")public class Person IdColumn(name="pid")private Integer id;Column(name="pname")private String name;public Integer getId() return id;public void setId(Integer id) this.id = id;public String getName() return name;public void setName(String name) this.name = name;JUNIT测试方法public EntityManager testGetEM()EntityManagerFactory emf = Persistence.createEntityManagerFactory("JPA");EntityManager em = emf.createEntityManager();return em;public void testAddPerson()Person p = new Person();p.setId(1);p.setName("ader");EntityManager em = testGetEM();EntityTransaction et = em.getTransaction();try et.begin();em.persist(p);mit(); catch (Exception e) e.printStackTrace(); MySQL测试数据库drop database if exists jpa;create database jpa;use jpa;drop table if exists person;drop table if exists ident;drop table if exists rel;create table person(pid int primary key auto_increment,pname varchar(50);create table ident(iid int primary key auto_increment,iname varchar(50);create table rel(personid int,identid int); JPA支持包antlr-2.7.6.jarcglib-2.1.3.jarclasses12.jarcommons-collections-3.1.jardom4j-1.6.1.jarehcache-1.2.3.jarejb3-persistence.jarhibernate3.jarhibernate-annotations.jarhibernate-cglib-repack-2.1_3.jarhibernate-commons-annotations.jarhibernate-entitymanager.jarjavassist-3.4.GA.jarjta-1.1.jarlog4j-1.2.15.jarpersistence-api-1.0.jarslf4j-api-1.5.2.jarslf4j-log4j12.jarHibernate核心包(8个文献):hibernate-distribution-3.3.1.GA.ZIP-hibernate3.jarlibbytecodecglibhibernate-cglib-repack-2.1_3.jar (CGLIB库,Hibernate用它来实现PO字节码的动态生成,非常核心的库,必须使用的jar包)librequired*.jarHibernate注解包(3个文献):hibernate-annotations-3.4.0.GA.ZIP-hibernate-annotations.jarlibejb3-persistence.jar, hibernate-commons-annotations.jarHibernate针对JPA的实现包(3个文献):hibernate-entitymanager-3.4.0.GA.ZIP-hibernate-entitymanager.jarlibtestlog4j.jar, slf4j-log4j12.jar数据库连接信息查询1、Hibernate JDBC属性 属性名 用途 hibernate.connection.driver_classjdbc驱动类hibernate.connection.urljdbc URLhibernate.connection.username数据库用户hibernate.connection.password数据库用户密码hibernate.dialect数据库方言2、驱动包Db2:db2java.jar(JDBC直连) :db2jcc.jar(Hibernate要用到此驱动jar文献和上面的驱动jar文献)sybase:jconn3d.jarMSSQL:msbase.jar+mssqlserver.jar+msutil.jarMySQL:mysql-connector-java-3.1.12-bin.jarOracle10g:ojdbc14.jar3、连接字符串(可以先添加驱动包然后到包里找Driver.class)a、MSSQL驱动:com.microsoft.jdbc.sqlserver.SQLServerDriver地址:jdbc:microsoft:sqlserver:/127.0.0.1:1433;DatabaseName=数据库b、Oracle10g驱动:oracle.jdbc.driver.OracleDriver地址:jdbc:oracle:thin:127.0.0.1:1521:全局标记符c、MySQL驱动:org.gjt.mm.mysql.Driver地址:jdbc:mysql:/127.0.0.1:3306/数据库d、Access驱动:sun.jdbc.odbc.JdbcOdbcDriver地址:jdbc:odbc:Driver=MicroSoft Access Driver (*.mdb);DBQ=c:demodb.mdbe、DB2驱动:COM.DB2Driver地址:jdbc:db2:/127.0.0.1:6789/demodb4、Hibernate SQL方言 (hibernate.dialect) RDBMS方言 DB2org.hibernate.dialect.DB2DialectDB2 AS/400org.hibernate.dialect.DB2400DialectDB2 OS390org.hibernate.dialect.DB2390DialectPostgreSQLorg.hibernate.dialect.PostgreSQLDialectMySQLorg.hibernate.dialect.MySQLDialectMySQL with InnoDBorg.hibernate.dialect.MySQLInnoDBDialectMySQL with MyISAMorg.hibernate.dialect.MySQLMyISAMDialectOracle (any version)org.hibernate.dialect.OracleDialectOracle 9i/10gorg.hibernate.dialect.Oracle9DialectSybaseorg.hibernate.dialect.SybaseDialectSybase Anywhereorg.hibernate.dialect.SybaseAnywhereDialectMicrosoft SQL Serverorg.hibernate.dialect.SQLServerDialectSAP DBorg.hibernate.dialect.SAPDBDialectInformixorg.hibernate.dialect.InformixDialectHypersonicSQLorg.hibernate.dialect.HSQLDialectIngresorg.hibernate.dialect.IngresDialectProgressorg.hibernate.dialect.ProgressDialectMckoi SQLorg.hibernate.dialect.MckoiDialectInterbaseorg.hibernate.dialect.InterbaseDialectPointbaseorg.hibernate.dialect.PointbaseDialectFrontBaseorg.hibernate.dialect.FrontbaseDialectFirebirdorg.hibernate.dialect.FirebirdDialect- 三、常用注解3.1 批注完全参考Entity要将 Java 类指定为 JPA 实体,请使用批注具体信息3.2 ID相关的复合主键需要1、 实现序列话2、 重写hascode、equal方法3、 有构造方法Embeddable 复合主键设立可以被引用EmbeddedId 引用独立复合主键ID3.3主键生成策略使用Hibernate的主键生成策略生成字符串主键IdGenericGenerator(name="generator",strategy="uuid")GeneratedValue(generator="generator")Column(name="id")使用Hibernate的主键生成策略与其他类共享主键IdGenericGenerator(name = "generator", strategy = "foreign", parameters = Parameter(name = "property", value = "person") ) GeneratedValue(generator = "generator")Column(name="cid")3.4字段、添加字段、添加表关联Column持久化字段可添加、可更新、可为空长度、表名、字段名、unique是否唯一JoinColumnname 列名referencedColumnName指向对象的列名unique约束唯一JoinColumns多个连接的列JoinColumns(JoinColumn(name="ADDR_ID", referencedColumnName="ID"),JoinColumn(name="ADDR_ZIP", referencedColumnName="ZIP") )JoinTableJoinTable(name="EJB_PROJ_EMP",joinColumns=JoinColumn(name="EMP_ID", referencedColumnName="ID"),inverseJoinColumns=JoinColumn(name="PROJ_ID", referencedColumnName="ID")3.5映射相关OneToOneManyToOneManyToManycascade级联、CURDfetch一次性所有读取相关对象,还是lazy加载optional 关联对象是否允许为空targetEntity关联对象3.6其他排序OrderBy("lastname ASC", "seniority DESC")共享主键PrimaryKeyJoinColumn标注为非持久话对象Transient时间类型Temporal(TemporalType.)枚举类型Enumerated(EnumType.)Lob /声明属性相应的是一个大文献数据字段。Basic(fetch = FetchType.LAZY) /设立为延迟加载,当我们在数据库中取这条记录的时候,不会去取-四、JPA映射4.1一对一映射4.1.1共享主键映射1、一端提供主键、一端共享主键设立生成策略generator,主键值gereratedValue(generator=”)uuid字符串IDforeign引用别人ID作为自己的主键(需要设立引用对象参数)2、oneToOnetargetEntity关联的目的对象,是类名.class形式fetch抓去策略,有关联的一起抓去、还是lazy加载cascade 级联mappedBy本对象被映射为*(在PrimaryKeyJoinColumn的另一端)3、PrimaryKeyJoinColumn设立在一端即可name 自身字段referenceColumnName指向对象的字段注意:只要一个PrimaryKeyJoinColumn,另一端的oneToOne 设立mappedBy都只有一个注意:1、向共享主键的对象设立提供主键的对象,然后持久化共享主键对象2、需要设立级联3、共享主键端维护关系、提供主键端被维护使用mappedByPerson提供主键Id GenericGenerator(name = "generator", strategy = "uuid") GeneratedValue(generator = "generator")Column(name="pid")private String id;Column(name="pname",length=2)private String name;OneToOne(mappedBy="person",fetch=FetchType.EAGER,targetEntity=Idcard.class)private Idcard idcard;Idcard共享主键IdGenericGenerator(name = "generator", strategy = "foreign", parameters = Parameter(name = "property", value = "person") ) GeneratedValue(generator = "generator")Column(name="cid")private String id;Column(name="cno")private String no;OneToOne(targetEntity=Person.class,fetch=FetchType.EAGER,cascade=CascadeType.ALL)PrimaryKeyJoinColumn(name="id",referencedColumnName="id")private Person person;IdGenericGenerator(name = "generator", strategy = "foreign", parameters = Parameter(name = "property", value = "person") ) GeneratedValue(generator = "generator")Column(name="cid")private String id;Column(name="cno")private String no;OneToOne(mappedBy="idcard",fetch=FetchType.EAGER,targetEntity=Person.class)private Person person;使用共享主键关联Person p = new Person();p.setName("ader");Idcard idcard = new Idcard();idcard.setNo("321321");idcard.setPerson(p);4.1.2关联外键映射关系的维护端OneToOne(级联)JoinColumn(name="本表中关联字段",referencedColumnName="指向字段")被维护端OneToOne(mappedBy=”)关系维护端添加一个字段作为外键指向被维护段。被维护端声明mappedByEntityTable(name="Test_Trousers")public class Trousers Id public Integer id; OneToOne JoinColumn(na