-
-
- 核心提示:JPA 注解的几个要点 1.设置Pojo为实体 @Entity //标识这个pojo是一个jpa实体 public class Users implements Serializable{ } 2.设置表名 @Entity @Table (name= users ) //指定表名为users public class Users implements Serializable{ } 3.设置主键 public
- JPA 注解的几个要点
- 1.设置Pojo为实体
- @Entity //标识这个pojo是一个jpa实体
- public class Users implements Serializable {
- }
- 2.设置表名
- @Entity
- @Table(name = "users") //指定表名为users
- public class Users implements Serializable {
- }
- 3.设置主键
- public class Users implements Serializable {
- @Id
- private String userCode;
- 4. 设置字段类型
- 通过@Column注解设置,包含的设置如下
- .name:字段名
- .unique:是否唯一
- .nullable:是否可以为空
- .inserttable:是否可以插入
- .updateable:是否可以更新
- .columnDefinition: 定义建表时创建此列的DDL
- .secondaryTable: 从表名。如果此列不建在主表上(默认建在主表),该属性定义该列所在从表的名字。
- @Column(name = "user_code", nullable = false, length=32)//设置属性userCode对应的字段为user_code,长度为32,非空
- private String userCode;
- @Column(name = "user_wages", nullable = true, precision=12, scale=2)//设置属性wages对应的字段为user_wages,12位数字可保留两位小数,可以为空
- private double wages;
- @Temporal(TemporalType.DATE)//设置为时间类型
- private Date joinDate;
- 5.字段排序
- 在加载数据的时候可以为其指定顺序,使用@OrderBy注解实现
- @Table(name = "USERS")
- public class User {
- @OrderBy(name = "group_name ASC, name DESC")
- private List books = new ArrayList();
- }
- 6.主键生成策略
- public class Users implements Serializable {
- @Id
- @GeneratedValue(strategy=GenerationType.IDENTITY)//主键自增,注意,这种方式依赖于具体的数据库,如果数据库不支持自增主键,那么这个类型是没法用的
- @Column(name = "user_id", nullable = false)
- private int userId;
- public class Users implements Serializable {
- @Id
- @GeneratedValue(strategy=GenerationType.TABLE)//通过一个表来实现主键id的自增,这种方式不依赖于具体的数据库,可以解决数据迁移的问题
- @Column(name = "user_code", nullable = false)
- private String userCode;
- public class Users implements Serializable {
- @Id
- @GeneratedValue(strategy=GenerationType.SEQUENCE)//通过Sequence来实现表主键自增,这种方式依赖于数据库是否有SEQUENCE,如果没有就不能用
- @SequenceGenerator(name="seq_user")
- @Column(name = "user_id", nullable = false)
- private int userId;
- 7.一对多映射关系
- 有T_One和T_Many两个表,他们是一对多的关系,注解范例如下
- 主Pojo
- @Entity
- @Table(name = "T_ONE")
- public class One implements Serializable {
- private static final long serialVersionUID = 1L;
- @Id
- @Column(name = "ONE_ID", nullable = false)
- private String oneId;
- @Column(name = "DESCRIPTION")
- private String description;
- @OneToMany(cascade = CascadeType.ALL, mappedBy = "oneId")//指向多的那方的pojo的关联外键字段
- private Collection<Many> manyCollection;
- 子Pojo
- @Entity
- @Table(name = "T_MANY")
- public class Many implements Serializable {
- private static final long serialVersionUID = 1L;
- @Id
- @Column(name = "MANY_ID", nullable = false)
- private String manyId;
- @Column(name = "DESCRIPTION")
- private String description;
- @JoinColumn(name = "ONE_ID", referencedColumnName = "ONE_ID")//设置对应数据表的列名和引用的数据表的列名
- @ManyToOne//设置在“一方”pojo的外键字段上
- private One oneId;
- 8.多对多映射关系
- 貌似多对多关系不需要设置级联,以前用hibernate的时候着实为多对多的级联头疼了一阵子,JPA的多对多还需要实际的尝试一下才能有所体会。
- 估计JPA的多对多也是可以转换成两个一对多的。
- 第一个Pojo
- @Entity
- @Table(name = "T_MANYA")
- public class ManyA implements Serializable {
- private static final long serialVersionUID = 1L;
- @Id
- @Column(name = "MANYA_ID", nullable = false)
- private String manyaId;
- @Column(name = "DESCRIPTION")
- private String description;
- @ManyToMany
- @JoinTable(name = "TMANY1_TMANY2", joinColumns = {@JoinColumn(name = "MANYA_ID", referencedColumnName = "MANYA_ID")}, inverseJoinColumns = {@JoinColumn(name = "MANYB_ID", referencedColumnName = "MANYB_ID")})
- private Collection<ManyB> manybIdCollection;
- 第二个Pojo
- @Entity
- @Table(name = "T_MANYB")
- public class ManyB implements Serializable {
- private static final long serialVersionUID = 1L;
- @Id
- @Column(name = "MANYB_ID", nullable = false)
- private String manybId;
- @Column(name = "DESCRIPTION")
- private String description;
- @ManyToMany(mappedBy = "manybIdCollection")
- private Collection<ManyA> manyaIdCollection;
- 9.一对一映射关系
- 主Pojo
- @Entity
- @Table(name = "T_ONEA")
- public class OneA implements Serializable {
- private static final long serialVersionUID = 1L;
- @Id
- @Column(name = "ONEA_ID", nullable = false)
- private String oneaId;
- @Column(name = "DESCRIPTION")
- private String description;
- @OneToOne(cascade = CascadeType.ALL, mappedBy = "oneA")//主Pojo这方的设置比较简单,只要设置好级联和映射到从Pojo的外键就可以了。
- private OneB oneB;
- 从Pojo
- @Entity
- @Table(name = "T_ONEB")
- public class OneB implements Serializable {
- private static final long serialVersionUID = 1L;
- @Id
- @Column(name = "ONEA_ID", nullable = false)
- private String oneaId;
- @Column(name = "DESCRIPTION")
- private String description;
- @JoinColumn(name = "ONEA_ID", referencedColumnName = "ONEA_ID", insertable = false, updatable = false)//设置从方指向主方的关联外键,这个ONEA_ID其实是表T_ONEA的主键
- @OneToOne
- private OneA oneA;
- 10 大字段
- @Lob //对应Blob字段类型
- @Column(name = "PHOTO")
- private Serializable photo;
- @Lob //对应Clob字段类型
- @Column(name = "DESCRIPTION")
- private String description;
- 11.瞬时字段
- 不需要与数据库映射的字段,在保存的时候不需要保存倒数据库
- @Transient
- private int tempValue;
- public int getTempValue(){
- get tempValue;
- }
- public void setTempValue(int value){
- this.tempValue = value;
- }
- JPA注解
- 关键字: jpa注解
- @Column
- 默认情况下,JPA 持续性提供程序假设每个实体的持久字段存储在其名称与持久字段的名称相匹配的数据库表列中。
- 使用 @Column 批注:
- 将持久字段与其他名称关联(如果默认列名难于处理、与事先存在的数据模型不兼容或作为数据库中的列名无效)
- 将持久字段与辅助表中的列关联(请参阅 @SecondaryTable )
- 微调数据库中列的特征
- 表 1-7 列出了此批注的属性 API 。。有关更多详细信息,请参阅
- 表 1-7 @Column 属性
- 属性 必需 说明
- columnDefinition
- 默认值 :空 String 。
- 默认情况下,JPA 使用最少量 SQL 创建一个数据库表列。
- 如果需要使用更多指定选项创建的列,请将 columnDefinition 设置为在针对列生成 DDL 时希望 JPA 使用的 SQL 片断。
- 注意 :捕获批注中的 DDL 信息时,某些 JPA 持续性提供程序可以在生成数据库模式时使用此 DDL。例如,请参阅“用于 Java2DB 模式生成的 TopLink JPA 扩展” 。
- insertable
- 默认值 :true 。
- 默认情况下,JPA 持续性提供程序假设所有列始终包含在 SQL INSERT 语句中。
- 如果该列不应包含在这些语句中,请将 insertable 设置为 false 。
- length
- 默认值 : 255
- 默认情况下,JPA 持续性提供程序假设所有列在用于保存 String 值时的最大长度为 255 个字符。
- 如果该列不适合于您的应用程序或数据库,请将 length 设置为适合于您的数据库列的 int 值。
- name
- 默认值 :JPA 持续性提供程序假设实体的每个持久字段都存储在其名称与持久字段或属性的名称相匹配的数据库表列中。
- 要指定其他列名,请将 name 设置为所需的 String 列名。
- nullable
- 默认值 :true 。
- 默认情况下,JPA 持续性提供程序假设允许所有列包含空值。
- 如果不允许该列包含空值,请将 nullable 设置为 false 。
- precision
- 默认值 : 0.
- 默认情况下,JPA 持续性提供程序假设所有列在用于保存十进制(精确数字)值时的精度为 0。
- 如果该精度不适合于您的应用程序或数据库,请将 precision 设置为相应的 int 精度。
- scale
- 默认值 : 0.
- 默认情况下,JPA 持续性提供程序假设所有列在用于保存十进制(精确数字)值时的伸缩度为 0。
- 如果该伸缩度不适合于您的应用程序或数据库,请将 scale 设置为相应的 int 精度。
- table
- 默认值 :JPA 持续性提供程序假设实体的所有持久字段都存储到一个其名称为实体名称的数据库表中(请参阅 @Table )。
- 如果该列与辅助表关联(请参阅 @SecondaryTable ),请将 name 设置为相应辅助表名称的 String 名称,如示例 1-8 所示。
- unique
- 默认值 :false 。
- 默认情况下,JPA 持续性提供程序假设允许所有列包含重复值。
- 如果不允许该列包含重复值,请将 unique 设置为 true 。设置为 true 时,这相当于在表级别使用 @UniqueConstraint 。
- updatable
- 默认值 :true 。
- 默认情况下,JPA 持续性提供程序假设列始终包含在 SQL UPDATE 语句中。
- 如果该列不应包含在这些语句中,请将 updatable 设置为 false 。
- 示例 1-8 显示了如何使用此批注使 JPA 将 empId 持久保存到辅助表 EMP_HR 中的列 EMP_NUM 。默认情况下,JPA 将 empName 持久保存到主表 Employee 中的列 empName 。
- <!---->
- 示例 1-8 @Column
- @Entity
- @SecondaryTable(name="EMP_HR")
- public class Employee implements Serializable {
- ...
- @Column(name="EMP_NUM", table="EMP_HR")
- private Long empId;
- private String empName;
- ...
- }
- <!---->
- @ColumnResult
- 执行
- 使用 @ColumnResult 批注返回标量值。标量类型由您在 @ColumnResult 中标识的列类型确定。
- 有关详细信息,另请参阅 @EntityResult 、@FieldResult 和 @SqlResultSetMapping 。
- 表 1-8 列出了此批注的属性 API 。。有关更多详细信息,请参阅
- 表 1-8 @ColumnResult 属性
- 属性 必需 说明
- name
- 在原生 SQL 查询的 SELECT 语句中将 name 设置为列名的 String 等效形式。如果在 SELECT 中使用列别名(AS 语句),则将 name 设置为列别名。
- 示例 1-9 显示了如何使用此批注将 Item (请参阅示例 1-10 )标量 name 包含在结果列表(请参阅示例 1-11 )中。在该示例中,结果列表将为 Object 数组的 List ,如:{[Order, "Shoes"], [Order, "Socks"], ...} 。
- <!---->
- 示例 1-9 使用 @ColumnResult 的 Order 实体
- @SqlResultSetMapping(
- name="OrderResults",
- entities={
- @EntityResult(
- entityClass=Order.class,
- fields={
- @FieldResult(name="id", column="order_id"),
- @FieldResult(name="quantity", column="order_quantity"),
- @FieldResult(name="item", column="order_item")
- }
- )
- },
- columns={
- @ColumnResult(
- name="item_name"
- )
- }
- )
- @Entity
- public class Order {
- @Id
- protected int id;
- protected long quantity;
- protected Item item;
- ...
- }
- 示例 1-10 Item 实体
- @Entity
- public class Item {
- @Id
- protected int id;
- protected String name;
- ...
- }
- 示例 1-11 结合使用 @SqlResultSetMapping 与 @ColumnResult 的原生查询
- Query q = entityManager.createNativeQuery(
- "SELECT o.id AS order_id, " +
- "o.quantity AS order_quantity, " +
- "o.item AS order_item, " +
- "i.name AS item_name, " +
- "FROM Order o, Item i " +
- "WHERE (order_quantity > 25) AND (order_item = i.id)",
- "OrderResults"
- );
- List resultList = q.getResultList();
- // List of Object arrays:{[Order, "Shoes"], [Order, "Socks"], ...}
- <!---->
- @DiscriminatorColumn
- 默认情况下,当
- 使用 @DiscriminatorColumn 批注:
- 指定一个标识符列名(如果数据模型中的列名不是默认列名 DTYPE )。
- 指定一个适用于应用程序或事先存在的数据模型的标识符列长度
- 微调数据库中的标识符列的特征
- 表 1-9 列出了此批注的属性 API 。。有关更多详细信息,请参阅
- 表 1-9 @DiscriminatorColumn 属性
- 属性 必需 说明
- columnDefinition
- 默认值 :空 String 。
- 默认情况下,JPA 持续性提供程序使用最少量 SQL 创建一个数据库表列。
- 如果需要使用更多指定选项创建的列,请将 columnDefinition 设置为在针对列生成 DDL 时希望 JPA 使用的 SQL 片断。
- discriminatorType
- 默认值 :DiscriminatorType.STRING 。
- 默认情况下,JPA 持续性提供程序假设标识符类型为 String 。
- 如果要使用其他类型,请将 discriminatorType 设置为 DiscriminatorType.CHAR 或 DiscriminatorType.INTEGER 。
- 您的 @DiscriminatorValue 必须符合此类型。
- length
- 默认值 : 31
- 默认情况下,JPA 持续性提供程序假设标识符列在用于保存 String 值时的最大长度为 255 个字符。
- 如果该列不适合于您的应用程序或数据库,请将 length 设置为适合于您的数据库列的 int 值。
- 您的 @DiscriminatorValue 必须符合此长度。
- name
- 默认值 :JPA 持续性提供程序假设标识符列名为“DTYPE ”。
- 要指定其他列名,请将 name 设置为所需的 String 列名。
- 示例 1-12 显示了如何使用此批注指定一个名为 DISC 、类型为 STRING 、长度为 20 的标识符列。在本示例中,该类的 @DiscriminatorValue 指定为 CUST 。示例 1-13 中的子类将它自己的 @DiscriminatorValue 指定为 VIP 。在 Customer 和 ValuedCustomer 中,@DiscriminatorValue 的值必须可以转换为由 @DiscriminatorColumn 属性 discriminatorType 指定的类型,并且必须符合 @DiscriminatorColumn 属性 length 。
- <!---->
- 示例 1-12 @DiscriminatorColumn 和 @DiscriminatorValue — 根类
- @Entity
- @Table(name="CUST")
- @Inheritance(strategy=SINGLE_TABLE)
- @DiscriminatorColumn(name="DISC", discriminatorType=STRING, length=20)
- @DiscriminatorValue(value-"CUST")
- public class Customer {
- ...
- }
- 示例 1-13 @DiscriminatorValue — 子类
- @Entity
- @DiscriminatorValue(value="VIP")
- public class ValuedCustomer extends Customer {
- ...
- }
- <!---->
- @DiscriminatorValue
- 默认情况下,当
- 使用 @DiscriminatorValue 批注指定用于区分此继承层次中的实体的标识符值:
- 如果实体名称不适合于此应用程序
- 匹配现有的数据库模式
- 表 1-10 列出了此批注的属性 API 。。有关更多详细信息,请参阅
- 表 1-10 @DiscriminatorValue 属性
- 属性 必需 说明
- value
- 将 value 设置为符合 @DiscriminatorColumn 属性 discriminatorType 和 length 的标识符值的 String 等效形式。
- 示例 1-14 显示了如何使用此批注指定一个名为 DISC 、类型为 STRING 、长度为 20 的标识符列。在本示例中,该类的 @DiscriminatorValue 指定为 CUST 。示例 1-15 中的子类将它自己的 @DiscriminatorValue 指定为 VIP 。在 Customer 和 ValuedCustomer 中,@DiscriminatorValue 的值必须可以转换为由 @DiscriminatorColumn 属性 discriminatorType 指定的类型,并且必须符合 @DiscriminatorColumn 属性 length 。
- <!---->
- 示例 1-14 @DiscriminatorColumn 和 @DiscriminatorValue — 根类
- @Entity
- @Table(name="CUST")
- @Inheritance(strategy=SINGLE_TABLE)
- @DiscriminatorColumn(name="DISC", discriminatorType=STRING, length=20)
- @DiscriminatorValue(value-"CUST")
- public class Customer {
- ...
- }
- 示例 1-15 @DiscriminatorValue — 子类
- @Entity
- @DiscriminatorValue(value="VIP")
- public class ValuedCustomer extends Customer {
- ...
- }
- <!---->
- @Embeddable
- 默认情况下,JPA 持续性提供程序假设每个实体均持久保存到它自己的数据库表。
- 使用 @Embeddable 批注指定一个类,该类的实例存储为拥有实体的固有部分并共享该实体的身份。嵌入对象的每个持久属性或字段都将映射到实体的数据库表。
- 此批注没有属性。有关更多详细信息,请参阅
- 示例 1-16 显示了如何使用此批注指定:类 EmploymentPeriod 在用作批注为 @Embedded 的持久字段的类型时可以嵌套到实体中(请参阅示例 1-17 )
- 示例 1-16 @Embeddable
- @Embeddable
- public class EmploymentPeriod {
- java.util.Date startDate;
- java.util.Date endDate;
- ...
- }
- <!---->
- @Embedded
- 默认情况下,JPA 持续性提供程序假设每个实体均持久保存到它自己的数据库表。
- 使用 @Embedded 批注指定一个持久字段,该字段的
- 可以结合使用 @Embedded 和 @Embeddable 以建立严格所有权关系的模型,以便在删除了拥有对象的情况下还将删除被拥有的对象。
- 嵌入的对象不应映射到多个表。
- 默认情况下,@Embeddable 类中指定的列定义(请参阅 @Column )适用于 @Embedded 类。如果要覆盖这些列定义,请使用 @AttributeOverride 。
- 此批注没有属性。有关更多详细信息,请参阅 API 。
- 示例 1-17 显示了如何使用该批注指定:@Embeddable 类 EmploymentPeriod (请参阅示例 1-16 )可以使用指定的属性覆盖(请参阅 @AttributeOverride )嵌入到实体类中。如果不需要属性覆盖,则可以完全忽略 @Embedded 批注:JPA 持续性提供程序将推断出 EmploymentPeriod 是从它的 @Embeddable 批注进行嵌套。
- 示例 1-17 @Embedded
- @Entity
- public class Employee implements Serializable {
- ...
- @Embedded
- @AttributeOverrides({
- @AttributeOverride(name="startDate", column=@Column("EMP_START")),
- @AttributeOverride(name="endDate", column=@Column("EMP_END"))
- )
- public EmploymentPeriod getEmploymentPeriod() {
- ...
- }
- ...
- }
- <!---->
- @EmbeddedId
- 使用 @EmbeddedId 批注指定一个由实体拥有的可嵌入复合主键类(通常由两个或更多基元类型或 JDK 对象类型组成)。从原有数据库映射时(此时数据库键由多列组成),通常将出现复合主键。
- 复合主键类具有下列特征:
- 它是一个普通的旧式 Java 对象 (POJO) 类。
- 它必须为 public,并且必须有一个 public 无参数构造函数。
- 如果使用基于属性的访问,则主键类的属性必须为 public 或 protected。
- 它必须是可序列化的。
- 它必须定义 equals 和 hashCode 方法。
- 这些方法的值相等性的语义必须与键映射到的数据库类型的数据库相等性一致。
- 或者,您可以使复合主键类成为非嵌入类(请参阅
- 此批注没有属性 API 。。有关更多详细信息,请参阅
- 示例 1-18 显示了一个批注为 @Embeddable 的典型复合主键类。示例1-19 显示了如何使用可嵌入的复合主键类(使用 @EmbeddedId 批注)配置一个实体。
- 示例 1-18 可嵌入复合主键类
- @Embeddable
- public class EmployeePK implements Serializable
- {
- private String name;
- private long id;
- public EmployeePK()
- {
- }
- public String getName()
- {
- return name;
- }
- public void setName(String name)
- {
- this.name = name;
- }
- public long getId()
- {
- return id;
- }
- public void setId(long id)
- {
- this.id = id;
- }
- public int hashCode()
- {
- return (int) name.hashCode() + id;
- }
- public boolean equals(Object obj)
- {
- if (obj == this) return true;
- if (!(obj instanceof EmployeePK)) return false;
- if (obj == null) return false;
- EmployeePK pk = (EmployeePK) obj;
- return pk.id == id && pk.name.equals(name);
- }
- }
- 示例 1-19 @EmbeddedId
- @Entity
- public class Employee implements Serializable
- {
- EmployeePK primaryKey;
- public Employee()
- {
- }
- @EmbeddedId
- public EmployeePK getPrimaryKey()
- {
- return primaryKey;
- }
- public void setPrimaryKey(EmployeePK pk)
- {
- primaryKey = pk;
- }
- ...
- }
- <!---->
- @Entity
- 使用 @Entity 批注将普通的旧式 Java 对象 (POJO) 类指定为实体,并使其可用于 JPA 服务。必须将 POJO 类指定为实体,然后才可以使用任何其他 JPA 批注。
- 表 1-11 @Entity 属性
- 属性 必需 说明
- name
- 默认值 :JPA 持续性提供程序假设实体名称是实体类的名称。在示例 1-20 中,默认 name 为“Employee ”。
- 如果实体类名难于处理、是一个保留字、与事先存在的数据模型不兼容或作为数据库中的表名无效,请将 name 设置为其他 String 值。
- 示例 1-20 显示了该批注的用法。
- <!---->
- 示例 1-20 @Entity
- @Entity
- public class Employee implements Serializable {
- ...
- }
- <!---->
- @EntityListeners
- 可以使用生命周期批注(请参阅
- 使用 @EntityListeners 批注将一个或多个实体监听程序类与 @Entity 或 @MappedSuperclass 关联,条件是您需要在指定的生命周期事件发生时执行逻辑,以及:
- 不希望在实体 API 中公开生命周期监听程序方法。
- 要在不同的实体类型之间共享生命周期监听程序逻辑。
- 当实体或子类上发生生命周期事件时,JPA 持续性提供程序将按监听程序定义的顺序通知每个实体监听程序,并调用使用相应的生命周期事件类型进行批注的实体监听程序方法(如果有)。
- 实体监听程序类具有以下特征:
- 它是一个普通的旧式 Java 对象 (POJO) 类
- 它有一个或多个具有以下签名的回调方法:
- public void <MethodName>(Object)
- 可以指定参数类型 Object ,或实体监听程序将与其关联的实体类的类型。
- 它用一个或多个生命周期事件批注对每个回调方法进行批注。
- 一个生命周期事件只能与一个回调监听程序方法关联,但某个给定的回调监听程序方法可以与多个生命周期事件关联。
- 如果使用实体监听程序,则可以管理哪些实体监听程序使用 @ExcludeDefaultListeners 和 @ExcludeSuperclassListeners 调用。
- 表 1-12 列出了此批注的属性 API 。。有关更多详细信息,请参阅
- 表 1-12 @EntityListeners 属性
- 属性 必需 说明
- value
- 要为 @Entity 或 @MappedSuperclass 指定实体监听程序类的列表,请将 value 设置为实体监听程序类的 Class 数组。
- 示例 1-21 显示了如何使用此批注将实体监听程序类 EmployeePersistListener (请参阅示例 1-22 )和 EmployeeRemoveListener (请参阅示例 1-23 )与实体 Employee 关联。示例 1-23 显示了您可以将多个生命周期事件与给定的实体监听程序类方法关联,但任何给定的生命周期事件只能在实体监听程序类中出现一次。
- <!---->
- 示例 1-21 @EntityListeners
- @Entity
- @EntityListeners(value={EmployeePersistListner.class, EmployeeRemoveListener.class})
- public class Employee implements Serializable {
- ...
- }
- 示例 1-22 EmployeePersistListener
- public class EmployeePersistListener {
- @PrePersist
- employeePrePersist(Object employee) {
- ...
- }
- ...
- }
- 示例 1-23 EmployeeRemoveListener
- public class EmployeeRemoveListener {
- @PreRemove
- @PostRemove
- employeePreRemove(Object employee) {
- ...
- }
- ...
- }
- <!---->
- @EntityResult
- 执行
- 使用 @EntityResult 批注返回实体。
- 有关详细信息,另请参阅 @ColumnResult 、@FieldResult 和 @SqlResultSetMapping 。
- 表 1-8 列出了此批注的属性 API 。。有关更多详细信息,请参阅
- 表 1-13 @EntityResult 属性
- 属性 必需 说明
- entityClass
- 将 entityClass 设置为由 SELECT 语句返回的实体的 Class 。
- discriminatorColumn
- 默认值 :空 String 。
- 默认情况下,JPA 持续性提供程序假设 SELECT 语句中不包含标识符列(请参阅 @Inheritance )。
- 如果在 SELECT 语句中使用标识符列,请将 discriminatorColumn 设置为所使用的 String 列名。
- fields
- 默认值 :空 FieldResult 数组。
- 默认情况下,JPA 持续性提供程序假设 SELECT 语句包含与返回的实体的所有字段或属性相对应的所有列,且 SELECT 语句中的列名对应于字段或属性名(未使用 AS 语句)。
- 如果 SELECT 语句只包含某些与返回的实体的字段或属性相对应的列,或 SELECT 语句中的列名并不对应于字段或属性名(使用了 AS 语句),请将 fields 设置为 @FieldResult 的数组,SELECT 语句中的每一列一个 @FieldResult 。
- 示例 1-24 显示了如何使用此批注将 Order 和 Item (请参阅示例 1-25 )实体包含在结果列表(请参阅示例 1-26 )中。在该示例中,结果列表将为 Object 数组的 List ,如:{[Order, Item], [Order, Item], ...} 。
- <!---->
- 示例 1-24 使用 @EntityResult 的 Order 实体
- @SqlResultSetMapping(
- name="OrderResults",
- entities={
- @EntityResult(
- entityClass=Order.class,
- fields={
- @FieldResult(name="id", column="order_id"),
- @FieldResult(name="quantity", column="order_quantity"),
- @FieldResult(name="item", column="order_item")
- }
- ),
- @EntityResult(
- entityClass=Item.class,
- fields={
- @FieldResult(name="id", column="item_id"),
- @FieldResult(name="name", column="item_name"),
- }
- )
- }
- )
- @Entity
- public class Order {
- @Id
- protected int id;
- protected long quantity;
- protected Item item;
- ...
- }
- 示例 1-25 Item 实体
- @Entity
- public class Item {
- @Id
- protected int id;
- protected String name;
- ...
- }
- 示例 1-26 结合使用 @SqlResultSetMapping 与 @EntityResult 的原生查询
- Query q = entityManager.createNativeQuery(
- "SELECT o.id AS order_id, " +
- "o.quantity AS order_quantity, " +
- "o.item AS order_item, " +
- "i.id AS item_id, " +
- "i.name AS item_name, " +
- "FROM Order o, Item i " +
- "WHERE (order_quantity > 25) AND (order_item = i.id)",
- "OrderResults"
- );
- List resultList = q.getResultList();
- // List of Object arrays:{[Order, Item], [Order, Item], ...}
- <!---->
- @Enumerated
- 默认情况下,JPA 持续性提供程序持久保存枚举常量的序数值。
- 使用 @Enumerated 批注指定在 String 值适合应用程序要求或与现有数据库模式匹配的情况下,JPA 持续性提供程序是否应持久保存枚举常量的序数值或 String 值。
- 该批注可以与
- @Basic 一起使用。
- <!---->
- <!---->
- <!---->
- <!---->@NamedNativeQuery 时,它可以返回实体(包括不同类型的实体)、标量值或实体和标量值的组合。
- <!---->
- <!---->
- <!---->
- <!---->生命周期事件批注 )指定实体中的方法,这些方法在指定的生命周期事件发生时执行您的逻辑。
- <!---->
- <!---->表 1-11 列出了此批注的属性 API 。。有关更多详细信息,请参阅
- <!---->
- <!---->
- <!---->@IdClass )。
- <!---->
- <!---->@Embeddable 类型可以存储为拥有实体的固有部分,并共享该实体的身份。嵌入对象的每个持久属性或字段均映射到拥有实体的数据库表。
- <!---->
- <!----> API 。
- <!---->
- <!---->
- <!---->@Inheritance 属性策略为 InheritanceType.SINGLE_TABLE 或 JOINED 时,JPA 持续性提供程序使用 @DiscriminatorColumn 按实体名称区分继承层次中的类(请参阅 @Entity )。
- <!---->
- <!---->
- <!---->@Inheritance 属性策略为 InheritanceType.SINGLE_TABLE 或 JOINED 时,JPA 持续性提供程序将创建一个名为 DTYPE 的标识符列以区分继承层次中的类。
- <!---->
- <!---->
- <!---->
- <!---->@NamedNativeQuery 时,它可以返回实体(包括不同类型的实体)、标量值或实体和标量值的组合。
- <!----><!---->
JPA作为Java EE的规范,它只是提供了一种标准的API。程序员若要使用JPA,仍需要选择JPA的实现框架。通过本章的学习,读者将能够了解与不同的JPA实现框架相关的知识,以便在实际的项目中做出合适的选择。
Hibernate是最流行的ORM框架之一,也是最早实现JPA的规范框架之一。它被JBoss收购后,目前作为JBoss的一个开源框架,它遵循LGPL v2.1开源许可协议,官方主页是http://www.hibernate.org/。
Hibernate 3.2以及以后的版本开始支持JPA,如图14-1所示为Hibernate框架包含的所有子项目。其中,涉及JPA的子项目有三个,它们分别是:
·Hibernate Core:Hibernate框架的核心实现。
·Hibernate Annotations:支持JDK 5.0的注释。
·Hibernate EntityManager:支持JPA的实现。
Hibernate JPA自定义配置可以通过多种方式进行配置,如下面列举的几种方法。
·方法一:在persistence.xml文件中配置,如下所示。
- <persistence>
- <persistence-unit name="jpaUnit" transaction-type="RESOURCE_LOCAL">
- <provider>org.hibernate.ejb.HibernatePersistence</provider>
- <properties>
- <property name="hibernate.connection.driver_class"value="com.mysql.jdbc.Driver" />
- <property name="hibernate.connection.url"value="jdbc:mysql://localhost:3306/jpademo" />
- <property name="hibernate.connection.username" value="root" />
- <property name=" hibernate.show_sql " value="true"/>
- </properties>
- </persistence-unit>
- </persistence>
- <persistence>
- <persistence-unit name="jpaUnit" transaction-type="RESOURCE_LOCAL">
- <provider>org.hibernate.ejb.HibernatePersistence</provider>
- <properties>
- <property name="hibernate.connection.driver_class"value="com.mysql.jdbc.Driver" />
- <property name="hibernate.connection.url"value="jdbc:mysql://localhost:3306/jpademo" />
- <property name="hibernate.connection.username" value="root" />
- <property name=" hibernate.show_sql " value="true"/>
- </properties>
- </persistence-unit>
- </persistence>
其中,“hibernate.show_sql ”为可配置的属性,Hibernate JPA还提供很多不同属性的配置。
·方法二:通过代码,在创建EntityManagerFactory时指定,如下所示。
Map configOverrides = new HashMap();
configOverrides.put("hibernate.format_sql ", true);
EntityManagerFactory programmaticEmf =
Persistence.createEntityManagerFactory("jpaUnit", configOverrides当同时使用方法一和方法二设置时,方法二的方式为有效的配置。
·方法三:使用Hibernate 专有的配置文件来配置,但首先要在persistence.xml文件中配置“hibernate.ejb.cfgfile”指定配置文件的位置,如下所示。
- <persistence>
- <persistence-unit name="jpaUnit" transaction-type="RESOURCE_LOCAL">
- <provider>org.hibernate.ejb.HibernatePersistence</provider>
- <properties>
- <property name="hibernate.connection.driver_class"value="com.mysql.jdbc.Driver" />
- <property name="hibernate.connection.url"value="jdbc:mysql://localhost:3306/jpademo" />
- <property name="hibernate.connection.username" value="root" />
- <!—可选,配置Hibernate配置文件-->
- < property name="hibernate.ejb.cfgfile" value="/com/fengmanfei/jpa/hibernate.cfg.xml"/ >
- </properties>
- </persistence-unit>
- </persistence>
- <persistence>
- <persistence-unit name="jpaUnit" transaction-type="RESOURCE_LOCAL">
- <provider>org.hibernate.ejb.HibernatePersistence</provider>
- <properties>
- <property name="hibernate.connection.driver_class"value="com.mysql.jdbc.Driver" />
- <property name="hibernate.connection.url"value="jdbc:mysql://localhost:3306/jpademo" />
- <property name="hibernate.connection.username" value="root" />
- <!—可选,配置Hibernate配置文件-->
- < property name="hibernate.ejb.cfgfile" value="/com/fengmanfei/jpa/hibernate.cfg.xml"/ >
- </properties>
- </persistence-unit>
- </persistence>
其中,“/com/fengmanfei/jpa/hibernate.cfg.xml”为Hibernate配置文件的保存位置。使用这种方式,适用于将现有Hibernate应用移植到JPA应用中来。但要注意,方法三的优先级最低,如果与方法一和方法二冲突,则方法一或方法二中的配置有效。
方法一和方法二是JPA的标准配置,方法三是Hibernate特有的配置。并不是所有的属性都可以通过这三种方式配置,其中一些属性必须通过方法一和方法二来配置,这些属性的详细说明如下所示。
·属性名:hibernate.ejb.classcache.<classname>
描述:指定缓存实体对象,<classname>为缓存类的全名,值为缓存类型,以逗号分隔。
示例如下:
<property name="hibernate.ejb.classcache. com.fengmanfei.jpa.entity.Customer" value="read-write"/>
·属性名:hibernate.ejb.collectioncache.<collectionrole>
描述:指定集合实体类缓存,设置同上。<collectionrole>为集合类的全名,值为缓存类型,以逗号分隔。
示例如下:
<property name="hibernate.ejb.collectioncache.com.fengmanfei.jpa.entity.Customer. orders"
value="read-write , RegionName "/>★ 提示 ★
读者若想了解更多的缓存设置,请参阅JBoss Cache的相关文档。
·属性名:hibernate.ejb.cfgfile
描述:指定使用Hibernate配置文件中的配置。
示例如下:
<property name="hibernate.ejb.cfgfile" value="/com/fengmanfei/jpa/hibernate.cfg.xml"/ >
·属性名:hibernate.archieve.autodetection
描述:创建Entity Manager时搜索文件的类型,多个值之间用逗号分隔。
可选值:
·class:.class类文件。
·hbm:Hibernate 配置文件。
默认两个都搜索。
示例如下:
<property name="hibernate.archive.autodetection" value="class,hbm"/>
·属性名:hibernate.ejb.interceptor
描述:自定义拦截器类名,拦截器必须实现了org.hibernate.Interceptor接口,并且有无参的构造方法。
示例如下:
<property name=" hibernate.ejb.interceptor " value="com.fengmanfei.jpa.interceptor.MyInterceptor"/>
·属性名:hibernate.ejb.naming_strategy
描述:设置注释命名策略。
可选值:
·EJB3NamingStrategy(默认):EJB3规范的命名实现。
·DefaultComponentSafeNamingStrategy:在默认的EJB3NamingStrategy上进行了扩展,允许在同一实体中使用两个同类型的嵌入对象而无须额外的声明。
示例如下:
<property name=" hibernate.ejb.naming_strategy " value=" DefaultComponentSafeNamingStrategy "/>
·属性名:hibernate.ejb.event.<eventtype>
描述:配置事件监听器,其中<eventtype>为监听的事件类型,事件类型如表14-1中列举所示。而值则为具体监听器类的全名,如果有多个则使用逗号分隔。自定义拦截器类,拦截器必须实现了org.hibernate.Interceptor接口,并且有无参的构造方法,在JPA的环境中,尽量继承表14-1中的时间监听器类。
表14-1 可选的监听事件类型
事件类型
监听器类
flush
org.hibernate.ejb.event.EJB3FlushEventListener
auto-flush
org.hibernate.ejb.event.EJB3AutoFlushEventListener
delete
org.hibernate.ejb.event.EJB3DeleteEventListener
flush-entity
org.hibernate.ejb.event.EJB3FlushEntityEventListener
merge
org.hibernate.ejb.event.EJB3MergeEventListener
create
org.hibernate.ejb.event.EJB3PersistEventListener
create-onflush
org.hibernate.ejb.event.EJB3PersistOnFlushEventListener
save
org.hibernate.ejb.event.EJB3SaveEventListener
save-update
org.hibernate.ejb.event.EJB3SaveOrUpdateEventListener
事件类型
监听器类
pre-insert
org.hibernate.secure.JACCPreInsertEventListener,org.hibernate.valitator.event.ValidateEventListener
pre-update
org.hibernate.secure.JACCPreUpdateEventListener,org.hibernate.valitator.event.ValidateEventListener
pre-delete
org.hibernate.secure.JACCPreDeleteEventListener
pre-load
org.hibernate.secure.JACCPreLoadEventListener
post-delete
org.hibernate.ejb.event.EJB3PostDeleteEventListener
post-insert
org.hibernate.ejb.event.EJB3PostInsertEventListener
post-load
org.hibernate.ejb.event.EJB3PostLoadEventListener
post-update
org.hibernate.ejb.event.EJB3PostUpdateEventListener
示例如下:
<property name="hibernate.ejb.event.create" value="com.fengmanfei.listener. CreateListener" />
其中,CreateListener继承org.hibernate.ejb.event.EJB3PersistEventListener类,代码如下所示。
package com.fengmanfei.listener;
import org.hibernate.HibernateException; import org.hibernate.ejb.event.EJB3PersistEventListener; import org.hibernate.event.PersistEvent;
public class CreateListener extends EJB3PersistEventListener {
// 覆盖父类中的方法 @Override public void onPersist(PersistEvent event) throws HibernateException { super.onPersist(event); //代码处理 } }
·属性名:hibernate.ejb.use_class_enhancer
描述:是否启用应用服务器扩展类。
可选值:
·true:启用扩展类。
·false(默认):禁用扩展类。
示例如下:
<property name=" hibernate.ejb.use_class_enhancer " value=" true”/>
·属性名:hibernate.ejb.discard_pc_on_close
描述:是否在执行clear()时脱离持久化上下文。
可选值:
·true:执行clear()时脱离持久化上下文。
·false(默认):执行clear()时不脱离持久化上下文。
示例如下:
<property name=" hibernate.ejb.discard_pc_on_close " value=" true”/>
Hibernate使用Apache commons-logging来为各种事件记录日志。commons-logging将直接将日志输出到Apache Log4j(如果在类路径中包括log4j.jar)或 JDK1.4 logging (如果运行在JDK1.4或以上的环境下)。
如果使用Log4j,需要将log4j.properties文件保存在类路径中。Hibernate根据对日志进行了详细的分类,以便能够控制日志的的输出信息,这些日志类别如表14-2所示。
表14-2 Hibernate JPA实现日志类别
属性名
描 述
org.hibernate.SQL
记录SQL DML语句
org.hibernate.type
记录JDBC参数
org.hibernate.tool.hbm2ddl
记录SQL DDL语句
org.hibernate.pretty
记录提交实体时,相关联的20个实体的状态
org.hibernate.cache
记录所有二级缓存
org.hibernate.transaction
记录事务相关的操作
org.hibernate.jdbc
记录获取JDBC资源的操作
org.hibernate.hql.ast.AST
记录HQL 和SQL AST的查询语句
org.hibernate.secure
记录JAAS认证请求
org.hibernate
记录所有信息,建议在调试开发阶段设置
例如,下面为log4j.properties配置日志的示例代码。
### log4j基本配置 ### log4j.appender.file=org.apache.log4j.FileAppender log4j.appender.file.File=hibernate.log log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### 设置日志级别### log4j.rootLogger=info, stdout ###输出hibernate调试过程中的错误日志 log4j.logger.org.hibernate=debug
###输出HQL查询调试日志 log4j.logger.org.hibernate.hql.ast.AST=debug
### 输出SQL语句调试日志 log4j.logger.org.hibernate.SQL=debug ### 输出 JDBC参数查询的日志 ### log4j.logger.org.hibernate.type=info
### 输出缓存日志 ### log4j.logger.org.hibernate.cache=debug
### 输出事务日志### log4j.logger.org.hibernate.transaction=debug
###输出获取JDBC资源日志### log4j.logger.org.hibernate.jdbc=debug
Hibernate除了自动对Session级别的事务进行一级缓存外,二级缓存的优化是Hibernate实现的一个亮点之一,有关二级缓存的属性如下所示。
属性名:hibernate.cache.provider_class
描述:二级缓存实现的类全名,所使用的缓存都需要实现org.hibernate.cache. CacheProvider接口,Hibernate已经实现了一些缓存,开发人员可以直接配置使用,同时要启用二级缓存,配置hibernate.cache.use_second_level_cache为true。
可选值:
org.hibernate.cache.HashtableCacheProvide、org.hibernate.cache.EhCacheProvider、org.hibernate.
cache.OSCacheProvider、org.hibernate.cache.SwarmCacheProvider和org.hibernate. cache.Tree CacheProvider等。
示例如下:
<property name=" hibernate.cache.provider_class " value=" org.hibernate.cache.HashtableCacheProvide "/>
★ 提示 ★
有关各种缓存实现的详细区别,读者可以参阅Hiberante Core的相关文档。
·属性名:hibernate.cache.use_minimal_puts
描述:是否优化二级缓存来最小化读写操作,集群时的缓存优化。
可选值:
·true(默认):启用最小化读写操作。
·false:禁用最小化读写操作。
示例如下:
<property name=" hibernate.cache.use_minimal_puts " value=" false”/>
·属性名:hibernate.cache.use_query_cache
描述:是否缓存查询结果。
可选值:
·true:缓存查询结果。
·false:不缓存查询结果。
示例如下:
<property name=" hibernate.cache.use_query_cache " value=" true”/>
·属性名:hibernate.cache.use_second_level_cache
描述:是否启用二级缓存。
可选值:
·true:启用二级缓存。
·false:不使用二级缓存。
示例如下:
<property name=" hibernate.cache.use_second_level_cache " value=" true”/>
·属性名:hibernate.cache.query_cache_factory
描述:设置自定义的查询缓存类全名,缓存类必须实现org.hibernate.cache.QueryCache接口。
可选值:
·org.hibernate.cache.StandardQueryCache(默认)。
·自定义缓存实现类。
示例如下:
<property name=" hibernate.cache.query_cache_factory " value=" com.fengmanfei.cache.MyCache”/>
·属性名:hibernate.cache.region_prefix
描述:二级缓存的前缀名称。
示例如下:
<property name=" hibernate.cache.region_prefix " value=" jpa”/>
·属性名:hibernate.cache.use_structured_entries
描述:是否使用结构化的方式缓存对象。
可选值:
·true:结构化方式缓存对象。
·false:不使用结构化的方式缓存对象。
示例如下:
<property name=" hibernate.cache.use_structured_entries " value=" true”/>
Hibernate自定义JDBC和数据库配置属性如下所示。
·属性名:hibernate.jdbc.fetch_size
描述:JDBC抓取记录的大小,相当于设置Statement.setFetchSize(),默认值为25。
示例如下:
<property name="hibernate.jdbc.fetch_size" value="50”/>
·属性名:hibernate.jdbc.batch_size
描述:JDBC2批量更新的大小,建议设置为5~30之间的值,默认为5。
示例如下:
<property name="hibernate.jdbc.batch_size" value=" 25”/>
·属性名:hibernate.jdbc.batch_versioned_data
描述:JDBC执行批量操作时,是否同时更新版本数据。
可选值:
·true(默认):执行批量操作executeBatch()返回成功的记录数,并且更新版本数据。
·false:批量操作后不更新版本数据。
示例如下:
<property name="hibernate.jdbc.batch_versioned_data" value="false”/>
·属性名:hibernate.jdbc.batch_versioned_data
描述:JDBC执行批量操作时,是否同时更新版本数据。
可选值:
·true(默认):执行批量操作executeBatch()返回成功的记录数,并且更新版本数据。
·false:批量操作后不更新版本数据。
示例如下:
<property name="hibernate.jdbc.batch_versioned_data" value="false”/>
·属性名:hibernate.jdbc.use_scrollable_resultset
描述:是否允许Hibernate使用JDBC2的可滚动结果集。
可选值:
·true(默认):可使用可滚动结果集,只有在使用用户提供的JDBC连接时,才需要设置为启用。
·false:不可使用滚动结果集。
示例如下:
<property name="hibernate.jdbc.use_scrollable_resultset" value="false”/>
·属性名:hibernate.jdbc.use_streams_for_binary
描述:是否JDBC以二进制方式读取。
可选值:
·true(默认):以二进制方式读取。
·false:以二进制方式读取,而以序列化方式读取。
示例如下:
<property name="hibernate.jdbc.use_streams_for_binary" value="false”/>
·属性名:hibernate.jdbc.use_get_generated_keys
描述:是否使用JDBC3插入记录时使用PreparedStatement.getGeneratedKeys()生成主键。
可选值:
·true:使用PreparedStatement.getGeneratedKeys()生成主键。
·false(默认):使用Hibernate自定义的生成策略。
示例如下:
<property name="hibernate.jdbc.use_get_generated_keys" value="true”/>
·属性名:hibernate.connection.isolation
描述:JDBC事务隔离级别,请读者查阅java.sql.Connection文档了解各个级别的类型,例如1、2、4(默认)、8。
示例如下:
<property name="hibernate.connection.isolation" value="8”/>
·属性名:hibernate.connection.autocommit
描述:是否使用JDBC自动提交。
可选值:
·true(默认):自动提交。
·false:不自动提交。
示例如下:
<property name="hibernate.connection.autocommit" value="false”/>
·属性名:hibernate.connection.driver_class
描述:数据连接的驱动类的全称,不同的数据库实现类不同。
示例如下:
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver”/>
·属性名:hibernate.connection.url
描述:数据连接的URL。
示例如下:
<property name="hibernate.connection.url" value=" jdbc:mysql://localhost:3306/ jpademo”/>
·属性名:hibernate.connection.username
描述:数据连接的用户名。
示例如下:
<property name="hibernate.connection.username " value="root”/>
·属性名:hibernate.connection.password
描述:数据连接的密码。
示例如下:
<property name="hibernate.connection.password " value="123”/>
·属性名:hibernate.dialect
描述:指定不同的数据库,Hibernate底层会根据不同的数据库生成的SQL进行优化,取值如表14-3所示。
表14-3 Hibernate JPA实现不同数据库相关配置的属性
属性名
描 述
DB2
org.hibernate.dialect.DB2Dialect
DB2 AS/400
org.hibernate.dialect.DB2400Dialect
DB2 OS390
org.hibernate.dialect.DB2390Dialect
PostgreSQL
org.hibernate.dialect.PostgreSQLDialect
MySQL
org.hibernate.dialect.MySQLDialect
MySQL InnoDB
org.hibernate.dialect.MySQLInnoDBDialect
MySQL with MyISAM
org.hibernate.dialect.MySQLMyISAMDialect
Oracle
org.hibernate.dialect.OracleDialect
Oracle 9i/10g
org.hibernate.dialect.Oracle9Dialect
Sybase
org.hibernate.dialect.SybaseDialect
Sybase Anywhere
org.hibernate.dialect.SybaseAnywhereDialect
Microsoft SQL Server
org.hibernate.dialect.SQLServerDialect
SAP DB
org.hibernate.dialect.SAPDBDialect
Informix
org.hibernate.dialect.InformixDialect
HypersonicSQL
org.hibernate.dialect.HSQLDialect
属性名
描 述
Ingres
org.hibernate.dialect.IngresDialect
Progress
org.hibernate.dialect.ProgressDialect
Mckoi SQL
org.hibernate.dialect.MckoiDialect
Interbase
org.hibernate.dialect.InterbaseDialect
Pointbase
org.hibernate.dialect.PointbaseDialect
示例如下:
<property name=" hibernate.dialect " value="org.hibernate.dialect.MySQLDialect”/>
除了前面几节列举的配置外,Hibernate的JPA实现还有一些常用的配置,如下所示。
·属性名:hibernate.show_sql
描述:是否输出SQL语句。
可选值:
·true(默认):输出SQL,相当于日志中设置org.hibernate.SQL的类别值为debug。
·false:不输出SQL。
示例如下:
<property name="hibernate.show_sql" value="false”/>
·属性名:hibernate.format_sql
描述:是否格式化输出SQL语句。
可选值:
·true(默认):格式化输出SQL。
·false:不格式化输出SQL。
示例如下:
<property name="hibernate.format_sql " value="false”/>
·属性名:hibernate.use_sql_comments
描述:是否输出SQL注释。
可选值:
·true(默认):输出SQL注释,有助于调试。
·false:不输出SQL注释。
示例如下:
<property name="hibernate.use_sql_comments" value="false”/>
·属性名:hibernate.generate_statistics
描述:是否收集与运行性能有关的参数。
可选值:
·true(默认):收集与运行性能有关的参数。
·false:不收集与运行性能有关的参数。
示例如下:
<property name="hibernate.generate_statistics" value="false"/>
·属性名:hibernate.hbm2ddl.auto
描述:对DDL的自动生成方式。
可选值:
·create-drop:删除后重新创建。
·create:只创建新的。
·update:更新。
·validate:只进行验证。
示例如下:
<property name=" hibernate.hbm2ddl.auto " value="create-drop"/>
·属性名:hibernate.default_schema
描述:生成的SQL默认的schema名称。
示例如下:
<property name="hibernate.default_schema" value="test"/>
·属性名:hibernate.default_catalog
描述:生成的SQL默认的catalog名称。
示例如下:
<property name="hibernate.default_catalog" value="test"/>
·属性名:hibernate.max_fetch_depth
描述:一对一和多对一映射时,实体加载的最大深度,0表示不抓取相关实体。建议值在0~3之间,默认为1。
示例如下:
<property name="hibernate.max_fetch_depth" value="2"/>
·属性名:hibernate.default_batch_fetch_size
描述:加载相关联的实体集合时,所加载的相关实体个数。建议使用2的倍数值,例如4、8(默认)、16。
示例如下:
<property name="hibernate.default_batch_fetch_size" value="16"/>
大多数情况下,Hibernate JPA中使用默认的设置就能基本满足需求,但当需求变化时,需要进行一些特殊的优化时,就可以通过自定义的一些属性来实现目标。
发布于 10个月前,阅读(234) | 评论(0) | 投票(0) | 收藏(2) 阅读全文... -
-
072012-09
现在的项目多数以数据去驱动。这样可以适应多种设备的调用。而在这里json格式是比较通用的。而在官方文档也说明了如何去转换你的json数据。(www.playframework.org/documentation/2.0.2/JavaJsonRequests) 而我在这里,是要和大家介绍更多的关于特殊情况的处理。如以下数据:
{ "introImg": "/assets/images/main/gdouIntro.jpg", "catalogName": "华师在线", "website": "http://www.gdou.com", "catalogID": 10000, "titileImg": "#", "mobileList": [{ "deviceCSS": "device device_iphone", "viewCSS": "view view_iphone", "minCSS": "minimg minimg_iphone", "deviceID": 500, "mobileIntro": "暂无", "showImg": "/assets/images/device/iphone/gdou/1.jpg", "showCSS": "display display_iphone", "downloadUrl": null, "deviceImg": "/assets/images/device/iphone.png", "bgCSS": "phone_bg", "menuCSS": "device_item item_iphone", "imgList": [{ "itemID": "5005", "picUrl": "/assets/images/device/iphone/gdou/1.jpg", "picID": 155 }, { "itemID": "5005", "picUrl": "/assets/images/device/iphone/gdou/2.jpg", "picID": 156 }, { "itemID": "5005", "picUrl": "/assets/images/device/iphone/gdou/3.jpg", "picID": 157 }, { "itemID": "5005", "picUrl": "/assets/images/device/iphone/gdou/4.jpg", "picID": 158 }, { "itemID": "5005", "picUrl": "/assets/images/device/iphone/gdou/5.jpg", "picID": 159 }], "deviceName": "iphone", "mobileID": 5005, "mobileName": "华师在线(iphone)", "bgImg": "/assets/images/device/phone_bg.jpg" },
json数组中某字段包含了另一个数组。我们必须要用一下方法处理://创建一个输出结果的容器
ArrayList jsonList= new ArrayList();//从数据层获取数据
List catalogList=GdouCatalog.GetCatalogByID(catalogID);//遍历所获得的数据
for(GdouCatalog item :catalogList){
Map
node.put("catalogID",item.catalogID);
node.put("catalogName",item.name);
node.put("intro",item.intro);
node.put("website",item.website);
node.put("logoImg",item.logoImg);
node.put("titileImg",item.titleImg);
node.put("introImg",item.introImg);
//二次遍历
ArrayList jsonMobileList= new ArrayList();
for(GdouMobileItem mobile:item.itemList)
{
Map
GdouMobile mobileInfo=GdouMobile.GetMobileInfo(mobile.mobileID);
mobileNode.put("deviceID",mobile.mobileID);
mobileNode.put("deviceName",mobileInfo.mobileName);
mobileNode.put("menuCSS",mobileInfo.menuCSS);
mobileNode.put("showCSS",mobileInfo.showCSS);
mobileNode.put("bgCSS",mobileInfo.bgCSS);
mobileNode.put("bgImg",mobileInfo.bgImg);
mobileNode.put("deviceImg",mobileInfo.deviceImg);
mobileNode.put("deviceCSS",mobileInfo.deviceCSS);
mobileNode.put("viewCSS",mobileInfo.viewCSS);
mobileNode.put("minCSS",mobileInfo.minCSS);
mobileNode.put("mobileID",mobile.itemID);
mobileNode.put("mobileName",mobile.name);
mobileNode.put("mobileIntro",mobile.intro);
mobileNode.put("downloadUrl",mobile.downloadUrl);
ArrayList imgList= new ArrayList();
int count=0;
for(GdouMobileImg img :mobile.imgList)
{
Map
imgNode.put("picID",img.picID);
imgNode.put("picUrl",img.picUrl);
imgNode.put("itemID",img.itemID);
imgList.add(imgNode);
if(count==0)
{
mobileNode.put("showImg",img.picUrl);
}
count++;
// jsonList.add(node);
}
mobileNode.put("imgList",imgList);
jsonMobileList.add(mobileNode);
}
node.put("mobileList",jsonMobileList);
jsonList.add(node);
}
发布于 10个月前,阅读(93) | 评论(0) | 投票(0) | 收藏(1) 阅读全文... -
072012-09
play framework 2.0 暂时不支持打包成war 。对于要部署到tomcat 还是有一定麻烦的,但是在git上还是有支持打包的方法。github.com/dlecan/play2-war-plugin 本文参考了使用指南进行了一次部署。下面是相关过程,希望对大家有帮助,
1. 要增加plugin.sbt 中的支持, 因为这是一个插件
resolvers += "Play2war plugins release" at "http://repository-play-war.forge.cloudbees.com/release/" addSbtPlugin("com.github.play2war" % "play2-war-plugin" % "0.7")
2. 对Build.scala 进行修改//新增头文件
import com.github.play2war.plugin._
//
val appVersion = "1.0-SNAPSHOT" val projectSettings = Play2WarPlugin.play2WarSettings ++ Seq( // Your settings Play2WarKeys.servletVersion := "3.0" //这里可以是2.5 看你使用的容器 ) ... val main = PlayProject( appName, appVersion, appDependencies, mainLang = JAVA ).settings(projectSettings: _*)
3. 添加日志 conf/logger.xml
<configuration>
<conversionRule conversionWord="coloredLevel" converterClass="play.api.Logger$ColoredLevel" />
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%date - [%level] - from %logger in %thread %n%message%n%xException%n</pattern>
</encoder>
</appender>
<logger name="play" level="TRACE" />
<logger name="application" level="INFO" />
<!-- Off these ones as they are annoying, and anyway we manage configuration ourself -->
<logger name="com.avaje.ebean.config.PropertyMapLoader" level="OFF" />
<logger name="com.avaje.ebeaninternal.server.core.XmlConfigLoader" level="OFF" />
<logger name="com.avaje.ebeaninternal.server.lib.BackgroundThread" level="OFF" />
<root level="ERROR">
<appender-ref ref="STDOUT" />
</root>
</configuration>
4. 编译生成war包 play package
5. 注意要把你的war包重命名放到你的tomcat webapp的根目录里。 (2.1 才支持在子目录,希望尽快发布)
发布于 10个月前,阅读(145) | 评论(0) | 投票(0) | 收藏(1) 阅读全文... -
072012-09
在Java开发中,spring可以说解决了不少问题。可以解决实体之间的问题。减少耦合度。在play framework 2.0中也可以应用上。对于spring 的模块加入首先我们需要在Build.scala中添加spring的包。
"play" % "spring_2.9.1" % "1.0-SNAPSHOT"
还要在application.conf中添加spring的模块支持:
spring.context = application-context.xml(这个是针对spring的配置文件,类之间的包含关系等。之后会说)
# Defaults to true
spring.namespace-aware = true
# Defaults to true
spring.add-play-properties = true
#spring.component-scan = beans
对于项目的结构我基本上是在app 新增services package(anyway 每个人在这里都有不同的使用。不喜欢的可以按照自己的方法)
//接口
public interface IGdouCatalogService {public ArrayList GetCatalogList();
public ArrayList GetCatalogByID(int catalogID);
}
//实现
public class GdouCatalogService implements IGdouCatalogService {
public ArrayList GetCatalogList()
{
ArrayList jsonList= new ArrayList();
List catalogList=GdouCatalog.GetCatalogList();
for(GdouCatalog item :catalogList)
{
Map
node.put("catalogID",item.catalogID);
node.put("catalogName",item.name);
node.put("intro",item.intro);
node.put("website",item.website);
node.put("img",item.img);
ArrayList jsonMobileList= new ArrayList();
for(GdouMobileItem mobile:item.itemList)
{
Map
mobileNode.put("mobileID",mobile.mobileID);
mobileNode.put("mobileName",mobile.name);
mobileNode.put("downloadUrl",mobile.downloadUrl);
jsonMobileList.add(mobileNode);
}
node.put("moibleList",jsonMobileList);
jsonList.add(node);
}
return jsonList;
}
public ArrayList GetCatalogByID(int catalogID)
{
ArrayList jsonList= new ArrayList();
List catalogList=GdouCatalog.GetCatalogByID(catalogID);
for(GdouCatalog item :catalogList)
{
Map
node.put("catalogID",item.catalogID);
node.put("catalogName",item.name);
node.put("intro",item.intro);
node.put("website",item.website);
node.put("img",item.img);
ArrayList jsonMobileList= new ArrayList();
for(GdouMobileItem mobile:item.itemList)
{
Map
mobileNode.put("mobileID",mobile.mobileID);
mobileNode.put("mobileName",mobile.name);
mobileNode.put("downloadUrl",mobile.downloadUrl);
jsonMobileList.add(mobileNode);
}
node.put("moibleList",jsonMobileList);
jsonList.add(node);
}
return jsonList;
}
}
通过从services的接口方法就可以通过controller进行调用。
public class Api extends Controller{
private IGdouCatalogService gdouCatalogService;
//增加构造函数接收 Service ,这里个人觉得正好是依赖注入的关键。
public Api(IGdouCatalogService gdouCatalogService)
{
this.gdouCatalogService=gdouCatalogService;
}
//这里还有一点我把所有controller的方法去除掉静态,后面会解释
@Transactional
@BodyParser.Of(play.mvc.BodyParser.Json.class)
public Result GetCatalogList(){
JsonNode json=request().body().asJson();
ObjectNode result = Json.newObject();
ArrayList jsonList= this.gdouCatalogService.GetCatalogList();
// return all as JSON
return ok(Json.toJson(jsonList));
}
@Transactional
@BodyParser.Of(play.mvc.BodyParser.Json.class)
public Result GetItemList(int catalogID){
JsonNode json=request().body().asJson();
ObjectNode result = Json.newObject();
ArrayList jsonList= this.gdouCatalogService.GetCatalogByID(10000);
// return all as JSON
return ok(Json.toJson(jsonList));
}
}
下面来看看 application-context.xml
这里注意需要诸如的类的关系,在api控制器中我们必须把构造方法与所带的函数关联上,有多少的函数就要绑定多少个bean。
这里我把controller作为spring的一部分所以我新增一个controllers/controllerFactory方法
public class ControllerFactory {
public static Api getApiController() {
return Spring.getBeanOfType(Api.class);
}
public static Application getAppController() {
return Spring.getBeanOfType(Application.class);
}
}
这个方法意味着我访问控制器时已经注入了相关的实例
这里需要修改route
# Home page
GET / controllers.ControllerFactory.getAppController.index()
# API Setting
GET /Api/GetCatalogList controllers.ControllerFactory.getApiController.GetCatalogList()
GET /Api/GetItemList/:catalogID controllers.ControllerFactory.getApiController.GetItemList(catalogID : Int)
//看这里应该明白我为何需要把控制器的静态方法去掉了吧。
哈哈这样就可以把你的东西和spring牢牢绑定了。
推荐看看这个文档会对你有帮助的。
github.com/scott-phillips/Spring4Play2
发布于 10个月前,阅读(137) | 评论(0) | 投票(0) | 收藏(1) 阅读全文... -
072012-09
虽然说是约定胜于配置但是一些基本的东西还是需要配置,希望下个版本节省得更多。我总结了一些希望对大家还是有帮助。
1.config/application.conf
在第一篇的时候,我说过config/application.conf是非常重要的东西,我在这里再说说
当我们去做数据库链接,还有hibernate,spring等配置时,传统的做法是配XML,非常的痛苦。毕竟这个东西出错了,就麻烦死了。而在play 所有的配置语法都在application.conf 中。
如果你想对数据库进行操作,只需要记住:
db.default.driver=你的JDBC驱动
db.default.url=链接串
db.default.user=用户名
db.default.pass=密码
而如果你是增加对JPA的支持,需要增加
db.default.jndiName=DefaultDS
jpa.default=defaultPersistenceUnit
如果增加ebean
ebean.default="models.*"
这里还有个重要的地方是当你使用现有数据库,而不需要将实体反向生成数据表时,必须使用:evolutionplugin=disabled
2. 一个我还是感到郁闷的地方
在Views中,应该是针对不同的Controller有不同的子目录这样才行,但是在现有的play2.0没有了(或者是我没有理解透)。那样不用愁,只需要在views目录里生成子目录就可以。不过这里有个细节就是必须要在命令行compile一次。否则是无效的。
3. config/route
这里是配置访问路由的地方,记得对每一个页面作配置,否则会出错。这里蛮失望的,因为asp.net mvc好呆也有默认值,如果我有100个页面。。。。。。希望下个版本改进!
4. views
关于页面模板,我不太想多说,你们要看还是看看官方的。我始终建议页面渲染还是交给javascript/css/html !!
发布于 10个月前,阅读(129) | 评论(0) | 投票(0) | 收藏(1) 阅读全文... -
072012-09
上一篇我把play framework的基本知识和搭建作了简短的介绍。现在我想说说Ebean。对数据库的操作,现行非常流行ORM。比较经典的技术Java的Hibernate,jpa ,还有基于.net 的 entityframework . 使用ORM,与使用rails模式一样。很大程度上简化了程序员的工作,更好地投入到代码当中。在play framework除了原有的JPA支持外,还支持了新的Ebean.
Ebean是一个使用纯Java实现的开源ORM框架。 Bean使用JPA注释(@entity, @OneToMany等Java注释)对实体进行映射。Ebean力求让使用最简单的API帮助开发者从数据库获取有用的数据信息。Ebean是一个对象/关系映射持久层框架。它与EJB3相类似,但该框架简单易于学习和使用。主要特点:兼容EJB3 ORM映射;支持级联保存和删除;支持懒加载;事务管理和日记功能;Statement Batching ;支持缓存;Clustering;集成Lucene文本搜索。在play framework中使用Ebean我们必须要在conf/application.conf中开启支持Ebean的语句。如下:
ebean.default="models.*"
对于Ebean的学习资料我推荐去Ebean的官网(www.avaje.org/),那里有不少的东西,我在这个博客就不多说了。
这里列一个例子让大家少走弯路。
我有两个数据表,GdouCatalog 和GdouMobileItem,这个是一个一对多的关系,如图:如果我要使用Ebean去做对应类,必须考虑他们之间的关系,因此有以下两个结构:
Ebean我的理解是对JPA的优化。因此一些相关的字段还是会保留下来,例如@Table , @OneToMany ,@ManyToOne,所以对于这些标签可以去翻查 JPA。 否则你会浪费很多的时间。当建立好ORM 关系后,你就必须添加相关的操作。如对GdouCatalog的操作,如图:
注意我在这里定义了一个默认的Finder目的是方便定义查询方法。至于语法,如果你有学习.net 那你就会觉得非擦好姑娘方便了(of coz ,总体是不同的,但是起码不用再写select,insert,update, delete了)。希望上面的例子对你们有帮助。
建议学习资料:
digitalsanctum.com/2012/06/01/play-framework-2-tutorial-ebean-orm/
发布于 10个月前,阅读(293) | 评论(0) | 投票(0) | 收藏(1) 阅读全文... -
072012-09
Play framework 是一个Rails风格的Full-stack Java Web框架。最近由于项目需求,所以终于把之前学习的应用上了。在这里与大家分享。在2.0开始,play framework 用scala进行了重构。新增加了不少特性。你可以用java语言进行编写外,也可以使用scala语言进行编写。不过本人还是倾向使用Java作为开发语言(主要是scala语言还要多看看)。
使用Play framework 当然是创建项目,列下以下步骤:
1. play new 你的项目名(当然你要配置好你的classpath)
2. 跳转到你的项目目录下,使用play
3. 选择你的IDE ,在下喜欢用IntelliJ 所以是输入idea
4. 当然是run 默认是9000端口,不过你也可以在命令行中修改 run 8080 就可以修改了。
在流行的Java框架中,很多人喜欢用ssh/传统的JavaEE进行开发,不过对于现代编程是非常不合适的。举个例子来说,你要使用strust+spring+hibernate ,需要配置一大堆的xml。每次修改都是一件痛苦的事情而且当我修改文件时需要大量的重新编译,非常麻烦。。在Rails的风格上使用约定胜于配置的方式,这样可以让程序员更多的关注代码而不是配置。还有使用Play开发时没有编译,打包和部署这些阶段,代之两个不同环境:用于开发阶段的DEV模式和用户部署阶段的PROD模式。Java源代码在运行时编译和加载。如果Java源文件在应用运行时发生改变,代码会重新编译并热加载(hot-swapped)到JVM中。模板文件也是如此。这样不用因为修改而去重新变异大量的代码节省了时间(haha 我说的所改即所得)。
Play framework 基于MVC的方式进行分布,约定model/views/controller放在指定app文件夹内(这里用package比较合适一点):
app/controllers
一个Controller就是一个Java 类,它的静态公共方法则是动作(Action)。动作是接收HTTP请求后的Java处理入口点。Controller类实际是面向过程的,非OO。Action从HTTP请求中提取数据,读或更新Model对象,然后返回一个包装成HTTP响应(HTTP Response)的结果。app/models
Model是一组具有所有OO特性的Java类。包含数据结构和应用可使用的操作。支持通过JPA,EBean持久化。app/views
应用的视图由Play的模板系统生成。Controller从Model获取数据,然后使用模板呈现它。此package包含HTML,XML等模板文件,用作动态生成模型的表述(Representation)。在play framework中,个人觉得有两个文件是比较重要的。
project/Build.scala
假若你需要引用一些功能时,你必须通过他进行运作。如想加入 hibernate,spring。通过他就可以在指定服务器中加载相关的插件。如图:
conf/applicaton.conf
如果你需要添加数据库等操作,这里就是关键了。当然你不需要去写xml,语法相当简练 ,如图:
如果你想更深入理解playframework 的搭建知识个人建议去git上的官方wiki,那里比较详细
github.com/playframework/Play20/wiki/
还有介绍下国外大牛的blog也是不错学习的地方,不过现在貌似和小弟一样都是刚开始写
发布于 10个月前,阅读(178) | 评论(0) | 投票(0) | 收藏(3) 阅读全文... -
312012-07
http://www.sproutmobi.com/
http://wrapbootstrap.com/
http://ajkochanowicz.github.com/Kickstrap/index.html
http://bootswatch.com/发布于 11个月前,阅读(1222) | 评论(0) | 投票(0) | 收藏(3) 阅读全文... -
262011-09
本文主要目的是用kindeditor 实现图片上传功能。
第一步:在view中加载kindeditor ,指定kindeditor的配置:
<script type="text/javascript">
KE.show({
id : 'content1',
//重点是下面这句
imageUploadJson : '@{Journals.uploadjson()}',
fileManagerJson : '../../jsp/file_manager_json.jsp',
allowFileManager : true,
afterCreate : function(id) {
KE.event.ctrl(document, 13, function() {
KE.util.setData(id);
document.forms['form'].submit();
});
KE.event.ctrl(KE.g[id].iframeDoc, 13, function() {
KE.util.setData(id);
document.forms['form'].submit();
});
}
});
</script>
第二步:编写Controller:uploadjson方法:
public static void uploadjson(File imgFile) {
//文件保存目录路径
String savePath = Play.applicationPath.toString()+Play.configuration.getProperty("newsImg.savePath", "false");
//文件保存目录URL
String saveUrl = Play.configuration.getProperty("newsImg.savePath", "false");
//System.out.println("Play.configuration.getProperty(newsImg.fileTypes):"+Play.configuration.getProperty("newsImg.fileTypes", "false"));
//定义允许上传的文件扩展名
String[] fileTypes = (Play.configuration.getProperty("newsImg.fileTypes", "false")).trim().toString().split(",");
//最大文件大小
long maxSize = 1000000;
if (imgFile != null) {
//检查目录
File uploadDir = new File(savePath);
if(!uploadDir.isDirectory()){
renderJSON(getError("上传目录不存在。"));
return;
}
//检查目录写权限
if(!uploadDir.canWrite()){
renderJSON(getError("上传目录没有写权限。"));
return;
}
//创建文件夹
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
String ymd = sdf.format(new Date());
savePath += ymd + "/";
saveUrl += ymd + "/";
File dirFile = new File(savePath);
if (!dirFile.exists()) {
dirFile.mkdirs();
}
//检查文件大小
if(imgFile.length() > maxSize){
renderJSON(getError("上传文件大小超过限制。"));
return;
}
//检查扩展名
String fileExt = imgFile.getName().substring(imgFile.getName().lastIndexOf(".") + 1).toLowerCase();
// System.out.println("fileExt:"+fileExt);
if(!Arrays.<String>asList(fileTypes).contains(fileExt)){
renderJSON(getError("上传文件扩展名是不允许的扩展名。"));
return;
}
// String ext = imgFile.getName().substring(
// imgFile.getName().lastIndexOf("."));
// String fileName = RandomStringUtils.random(8, true, true) + ext;
SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
String newFileName = df.format(new Date()) + "_" + new Random().nextInt(1000) + "." + fileExt;
File f = new File(savePath,newFileName);
//System.out.println("f.getPath()----:" + f.getPath());
try {
// System.out
// .println("imgFile.renameTo(f):" + imgFile.renameTo(f));
JSONObject obj = new JSONObject();
obj.put("error", 0);
obj.put("url", saveUrl + newFileName);
renderText(obj.toJSONString().toString());
return;
} catch (Exception e) {
e.printStackTrace();
renderJSON(getError("上传失败"));
return;
}
}else{
renderJSON(getError("请选择文件。"));
return;
}
}
第三步:测试吧。就这些了,不用详细介绍了。
发布于 1年前,阅读(504) | 评论(1) | 投票(0) | 收藏(4) 阅读全文... -
132010-10
如下图:通常我们在struts2中实现这个效果,并且取得值是很方便的。在前台jsp页面中定义<input type="text" class="input01" maxlength="30" name="userPhoneVo["+phoneSeq+"].phoneNumber" />
在action中定义一个
private List<UserPhoneVo> userPhoneVo = new ArrayList<UserPhoneVo>();
这样就可以取得每一组中各个字段的值了。
【转载】jpa 注解2
最新推荐文章于 2021-01-14 12:28:49 发布