JPA 的 @Enumerated 注解非常好用,用来直接映射 enum 枚举类型的字段。@Enumerated 注解可以与 @Basic 注解一起使用,或者当元素集合值是基本类型时,可以与 @ElementCollection 注解一起使用。如果未指定枚举类型或未使用 @Enumerated 注解,则假定 EnumType 值为 ORDINAL。
@Enumerated 注解源码如下:
@Target({METHOD, FIELD}) @Retention(RUNTIME) public @interface Enumerated { // 指定映射枚举的类型,默认为 ORDINAL EnumType value() default ORDINAL; }
EnumType 枚举定义了枚举类型的映射。此枚举类型的常量指定如何持久化枚举类型的持久属性或字段。可选值如下:
ORDINAL:将枚举类型属性或字段持久化为整数;
STRING:将枚举类型属性或字段持久化为字符串;
源码:
public enum EnumType { // 映射枚举字段的下标 ORDINAL, // 映射枚举字段的name STRING }
(1)创建 users4 表,该表添加了性别枚举字段。SQL 脚本如下:
CREATE TABLE `users4` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID', `name` varchar(255) DEFAULT NULL COMMENT '姓名', `sex` int(10) unsigned DEFAULT NULL COMMENT '年龄', PRIMARY KEY (`id`) ) DEFAULT CHARSET=utf8;
(2)定义用户性别枚举类型,代码如下:
public enum SexEnum { MALE("男"), FEMALE("女"); private String value; private SexEnum(String value) { this.value = value; } }
(3)定义实体,使用 @Enumerated 注解修饰 sex 属性/字段是一个 SexEnum 枚举类型,同时使用枚举的下标作为映射值。代码如下:
import lombok.Data; import javax.persistence.*; @Data @Entity @Table(name = "users4") public class User13 { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; @Column private String name; @Column @Enumerated(EnumType.ORDINAL) private SexEnum sex; }
(4)客户端将向 users4 表插入两条数据,性别分别为 SexEnum.MALE 和 SexEnum.FEMALE。然后使用 select 语句将刚刚插入的数据查询出来。代码如下:
import com.alibaba.fastjson.JSONObject; import com.huangx.openjpa.annotation.entity.SexEnum; import com.huangx.openjpa.annotation.entity.User13; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import javax.persistence.Query; import java.util.List; public class OpenJpaDemo13 { /** 持久化单元名称 */ private static final String NAME = "openJPA"; public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory(NAME); EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); // INSERT User13 user = new User13(); user.setName("李四-" + System.currentTimeMillis()); user.setSex(SexEnum.MALE); em.persist(user); user = new User13(); user.setName("李四2-" + System.currentTimeMillis()); user.setSex(SexEnum.FEMALE); em.persist(user); System.out.println("insert finished."); // SELECT String qlString = "select t from User13 t"; Query query = em.createQuery(qlString); List<User13> userList = (List<User13>) query.getResultList(); for (User13 item : userList) { System.out.println(JSONObject.toJSONString(item)); } em.getTransaction().commit(); em.close(); emf.close(); System.out.println("finished."); } }
运行上面客户端代码,执行完成后数据库添加了两条数据,如下图:
其中,id=151 的用户 sex 为 0(SexEnum.MALE 枚举的下标);id=152 的用户 sex 为 1(SexEnum.FEMALE 的下标)。控制台输出如下:
{"id":151,"name":"李四-1622697304567","sex":"MALE"} {"id":152,"name":"李四2-1622697304660","sex":"FEMALE"}
如果我们将实体的 sex 属性上的 @Enumerated 改为 EnumType.STRING 方式,代码如下:
import lombok.Data; import javax.persistence.*; @Data @Entity @Table(name = "users4") public class User13 { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; @Column private String name; @Column @Enumerated(EnumType.STRING) private SexEnum sex; }
记住,这里需要将数据表 sex 字段改为 varchar 类型。SQL 脚本如下:
CREATE TABLE `users4` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID', `name` varchar(255) DEFAULT NULL COMMENT '姓名', `sex` varchar(20) DEFAULT NULL COMMENT '年龄', PRIMARY KEY (`id`) ) DEFAULT CHARSET=utf8;
再次运行客户端代码,将数据库中添加如下两条数据:
上面添加的两条用户信息的 sex 字段使用的是枚举 name(注意:是 MALE/FEMALE 不是具体的 “男/女”)。在实际工作中,我们经常会用 EnumType.STRING,如果使用 EnumType.ORDINAL,当我们在枚举类中添加新的枚举值,或枚举值顺序变了,数据库中保存的顺序值就不能与以前的值对应了。控制台输出如下:
{"id":301,"name":"李四-1622697989769","sex":"MALE"} {"id":302,"name":"李四2-1622697989836","sex":"FEMALE"}