Hibernate继承注解

hibernate应用中,继承的用途或目的主要有两点:

  • 组件化:故明思义,把重复性的代码抽取成组件,以便重用和维护。hibernate应用中,一些重复的字段,重复的映射配置,就需要抽取成组件。
  • 多态性:类的多态性是指下层业务所需一个父类对象,而上层业务根据所需的父类对象,传递一个子类对象。hibernate应用中,下层业务操作父类对象进行持久操作,如增删改查,上层业务则传递一个子类对象。

 

所以,在应用hibernate的继承时,需要明确设计所需,即究竟是组件化需求,还是多态性需求。

  • @MappedSuperclass:组件化需求的继承注解。虽然它可以应用于类的多态性业务中,但它不能应用于hibernate持久操作的多态性业务中。
  • @Inheritance:多态性需求的继承注解。虽然它可以达到组件化的目的,但它要比@MappedSuperclass多负出一些代价。

 

@MappedSuperclass定义:

@Documented
@Target({TYPE})
@Retention(RUNTIME)
public @interface MappedSuperclass {
}

 

@Inheritance定义:

@Target({TYPE})
@Retention(RUNTIME)
public @interface Inheritance {
    InheritanceType strategy() default SINGLE_TABLE;
}

InheritanceType定义:

public enum InheritanceType { 
    SINGLE_TABLE, 
    TABLE_PER_CLASS, 
    JOINED 
}

从定义看出,@Inheritance的默认继承策略为SINGLE_TABLE,三种继承策略的区别在于:

  • SINGLE_TABLE:公共属性公共表,独立属性公共表。
    需要使用监别器区分具体的子类,注解@DiscriminatorColumn设置监别器列,注解@DiscriminatorValue设置监别器值。
    子类的属性映射配置时,需要设置为允许为空或默认值。
  • JOINED:公共属性公共表,独立属性独立表。
    子类的独立表生成后,其主键是一个共享主键,意味着这是一对一的关联,默认名称与父类的主键一致,使用注解@PrimaryKeyJoinColumn可改变名称。
  • TABLE_PER_CLASS:公共属性独立表,独立属性独立表。
    主键生成策略不能使用GenerationType.IDENTITY。

对于子类而言,公共属性就是父类的属性,公共表就是父类对应的表,而独立属性就是自己定义的属性,独立表就是自己对应的表。

 

示例1:继承注解@MappedSuperclass

User.java

@MappedSuperclass
public class User<ID extends Serializable> {
    //---------------------------------------------------------------
    // Field
    //---------------------------------------------------------------
    
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private ID id;
    
    @Column(name = "loginName",
            length = 20,
            unique = true,
            nullable = false,  
            updatable = false)
    private String loginName;
    
    @Column(name = "loginPass",
            length = 20,
            nullable = false)
    private String loginPass;
    
    //---------------------------------------------------------------
    // Method
    //---------------------------------------------------------------
    
    public ID getId() {
        return id;
    }

    public void setId(ID id) {
        this.id = id;
    }
    
    public String getLoginName() {
        return loginName;
    }

    public void setLoginName(String loginName) {
        this.loginName = loginName;
    }

    public String getLoginPass() {
        return loginPass;
    }

    public void setLoginPass(String loginPass) {
        this.loginPass = loginPass;
    }
}

Admin.java

@Entity
@Table
public class Admin extends User<Integer> {
    @Column(name = "role", length = 20, nullable = false)
    private String role;

    public String getRole() {
        return role;
    }

    public void setRole(String role) {
        this.role = role;
    }
}

Member.java

@Entity
@Table
public class Member extends User<Long> {
    @Column(name = "name", length = 20, nullable = false)
    private String name;

    public String getName() {
        return name;
    }

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

test.java

public class Test {
    public static void main(String[] params){
        // 继承注解:@MappedSuperclass
        new Test().test();
        /*
            Hibernate: 
                drop table if exists Admin
                
            Hibernate: 
                drop table if exists Member
                
            Hibernate: 
                create table Admin (
                   id integer not null auto_increment,
                    loginName varchar(20) not null,
                    loginPass varchar(20) not null,
                    role varchar(20) not null,
                    primary key (id)
                )
                
            Hibernate: 
                create table Member (
                   id bigint not null auto_increment,
                    loginName varchar(20) not null,
                    loginPass varchar(20) not null,
                    name varchar(20) not null,
                    primary key (id)
                )
                
            Hibernate: 
                alter table Admin 
                   add constraint UK_bdsh7mq6s6xad6ohm08u18uxr unique (loginName)
                   
            Hibernate: 
                alter table Member 
                   add constraint UK_jxtse8o1c6l89j39lilw5e2rs unique (loginName)
                   
            Hibernate: 
                insert 
                into
                    Admin
                    (loginName, loginPass, role) 
                values
                    (?, ?, ?)
                    
            Hibernate: 
                select
                    last_insert_id()
                    
            Hibernate: 
                drop table if exists Admin
                
            Hibernate: 
                drop table if exists Member
     */
    }

    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml", this.getClass());
        SessionFactory factory = null;
        boolean success = true;
        Session session = null;
        try {
            factory = (SessionFactory) context.getBean("sessionFactory");
            session = factory.openSession();
            success = false;
            session.beginTransaction();
            User<?> user = new Admin();
            user.setLoginName("loginName");
            user.setLoginPass("loginPass");
            ((Admin)user).setRole("role");
            session.save(user);
            session.getTransaction().commit();
            success = true;
        } finally {
            if(session != null){
                if(!success)
                    session.getTransaction().rollback();
                session.close();
                session = null;
            }
            
            if(factory != null){
                factory.close();
                factory = null;
            }
        }
    }
}

 

示例2:继承注解@Inheritance,继承策略InheritanceType.SINGLE_TABLE。

User.java

@Entity
@Table
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(
        name = "type",
        discriminatorType = DiscriminatorType.STRING,
        length = 30)
@DiscriminatorValue("User")
public class User {
    //---------------------------------------------------------------
    // Field
    //---------------------------------------------------------------
    
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(name = "loginName",
            length = 20,
            unique = true,
            nullable = false,  
            updatable = false)
    private String loginName;
    
    @Column(name = "loginPass",
            length = 20,
            nullable = false)
    private String loginPass;
    
    //---------------------------------------------------------------
    // Method
    //---------------------------------------------------------------
    
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
    
    public String getLoginName() {
        return loginName;
    }

    public void setLoginName(String loginName) {
        this.loginName = loginName;
    }

    public String getLoginPass() {
        return loginPass;
    }

    public void setLoginPass(String loginPass) {
        this.loginPass = loginPass;
    }
}

Admin.java

@Entity
@DiscriminatorValue("Admin")
public class Admin extends User {
    // 需要允许为空或设置默认值
    @Column(name = "role", length = 20, nullable = true)
    private String role;

    public String getRole() {
        return role;
    }

    public void setRole(String role) {
        this.role = role;
    }
}

Member.java

@Entity
@DiscriminatorValue("Member")
public class Member extends User {
    // 需要允许为空或设置默认值
    @Column(name = "name", length = 20, nullable = false, columnDefinition="VARCHAR(20) DEFAULT 'admin'")
    private String name;

    public String getName() {
        return name;
    }

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

Test.java

public class Test {
    public static void main(String[] params){
        // 继承注解:@Inheritance
        // 继承策略:InheritanceType.SINGLE_TABLE
        // 公共属性公共表,独立属性公共表
        new Test().test();
        /*
            Hibernate: 
                drop table if exists User
                
            Hibernate: 
                create table User (
                   type varchar(30) not null,
                    id bigint not null auto_increment,
                    loginName varchar(20) not null,
                    loginPass varchar(20) not null,
                    role VARCHAR(20) DEFAULT 'member' not null,
                    name VARCHAR(20) DEFAULT 'admin' not null,
                    primary key (id)
                )
                
            Hibernate: 
                alter table User 
                   add constraint UK_5iebj9qwxsnoshbaq6w834t0y unique (loginName)
                   
            Hibernate: 
                insert 
                into
                    User
                    (loginName, loginPass, role, type) 
                values
                    (?, ?, ?, 'Admin')
                    
            Hibernate: 
                select
                    last_insert_id()
                    
            Hibernate: 
                select
                    user0_.id as id2_0_0_,
                    user0_.loginName as loginNam3_0_0_,
                    user0_.loginPass as loginPas4_0_0_,
                    user0_.role as role5_0_0_,
                    user0_.name as name6_0_0_,
                    user0_.type as type1_0_0_ 
                from
                    User user0_ 
                where
                    user0_.id=?
                    
            多态性读取成功:study.t2.Admin@dc3aae
            
            Hibernate: 
                drop table if exists User
         */
    }

    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml", this.getClass());
        SessionFactory factory = null;
        try {
            factory = (SessionFactory) context.getBean("sessionFactory");
            
            // 多态性添加
            boolean success = true;
            Session session = null;
            Long id = null;
            try {
                session = factory.openSession();
                success = false;
                session.beginTransaction();
                User user = new Admin();
                user.setLoginName("loginName");
                user.setLoginPass("loginPass");
                ((Admin)user).setRole("role");
                session.save(user);
                session.getTransaction().commit();
                id = user.getId();
                success = true;
            } finally {
                if(session != null){
                    if(!success)
                        session.getTransaction().rollback();
                    session.close();
                    session = null;
                }
            }

            // 多态性读取
            if(success){
                try {
                    session = factory.openSession();
                    session.beginTransaction();
                    success = false;
                    User user = session.load(User.class, id);
                    System.out.println("多态性读取成功:" + user);
                    session.getTransaction().commit();
                    success = true;
                } finally {
                    if(session != null){
                        if(!success)
                            session.getTransaction().rollback();
                        session.close();
                        session = null;
                    }
                }
            }
        } finally {
            if(factory != null){
                factory.close();
                factory = null;
            }
        }
    }
}

 

示例3:继承注解@Inheritance,继承策略InheritanceType.JOINED。

User.java

@Entity
@Table
@Inheritance(strategy = InheritanceType.JOINED)
public class User {
    
    //---------------------------------------------------------------
    // Field
    //---------------------------------------------------------------
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(name = "loginName",
            length = 20,
            unique = true,
            nullable = false,  
            updatable = false)
    private String loginName;
    
    @Column(name = "loginPass",
            length = 20,
            nullable = false)
    private String loginPass;
    
    //---------------------------------------------------------------
    // Method
    //---------------------------------------------------------------
    
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
    
    public String getLoginName() {
        return loginName;
    }

    public void setLoginName(String loginName) {
        this.loginName = loginName;
    }

    public String getLoginPass() {
        return loginPass;
    }

    public void setLoginPass(String loginPass) {
        this.loginPass = loginPass;
    }
}

Admin.java

@Entity
@Table
// 可选,设置共享主键的名称,默认的主键名称与父类一致。
@PrimaryKeyJoinColumn(name = "userId")
public class Admin extends User {
    @Column(name = "role", length = 20, nullable = false)
    private String role;

    public String getRole() {
        return role;
    }

    public void setRole(String role) {
        this.role = role;
    }
}

Member.java

@Entity
@Table
// 可选,设置共享主键的名称,默认的主键名称与父类一致。
@PrimaryKeyJoinColumn(name = "userId")
public class Member extends User {
    @Column(name = "name", length = 20, nullable = false)
    private String name;

    public String getName() {
        return name;
    }

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

Test.java

public class Test {
    public static void main(String[] params){
        // 继承注解:@Inheritance
        // 继承策略:InheritanceType.JOINED
        // 公共属性公共表,独立属性独立表
        new Test().test();
        /*
            Hibernate: 
                alter table Admin 
                   drop 
                   foreign key FKjoav33p64suikub3369fpajy4
            
            注:这里可能报一个异常,因为表Admin不存在!
            
            Hibernate: 
                alter table Member 
                   drop 
                   foreign key FKnj6wlxlj0cc3993su1qaykn42
            
            注:这里可能报一个异常,因为表Member不存在!
            
            Hibernate: 
                drop table if exists Admin
                
            Hibernate: 
                drop table if exists Member
                
            Hibernate: 
                drop table if exists User
                
            Hibernate: 
                create table Admin (
                   role varchar(20) not null,
                    userId bigint not null,
                    primary key (userId)
                )
                
            Hibernate: 
                create table Member (
                   name varchar(20) not null,
                    userId bigint not null,
                    primary key (userId)
                )
                
            Hibernate: 
                create table User (
                   id bigint not null auto_increment,
                    loginName varchar(20) not null,
                    loginPass varchar(20) not null,
                    primary key (id)
                )
                
            Hibernate: 
                alter table User 
                   add constraint UK_5iebj9qwxsnoshbaq6w834t0y unique (loginName)
                   
            Hibernate: 
                alter table Admin 
                   add constraint FKjoav33p64suikub3369fpajy4 
                   foreign key (userId) 
                   references User (id)
                   
            Hibernate: 
                alter table Member 
                   add constraint FKnj6wlxlj0cc3993su1qaykn42 
                   foreign key (userId) 
                   references User (id)
                   
            Hibernate: 
                insert 
                into
                    User
                    (loginName, loginPass) 
                values
                    (?, ?)
                    
            Hibernate: 
                select
                    last_insert_id()
                    
            Hibernate: 
                insert 
                into
                    Admin
                    (role, userId) 
                values
                    (?, ?)
                    
            Hibernate: 
                select
                    user0_.id as id1_2_0_,
                    user0_.loginName as loginNam2_2_0_,
                    user0_.loginPass as loginPas3_2_0_,
                    user0_1_.role as role1_0_0_,
                    user0_2_.name as name1_1_0_,
                    case 
                        when user0_1_.userId is not null then 1 
                        when user0_2_.userId is not null then 2 
                        when user0_.id is not null then 0 
                    end as clazz_0_ 
                from
                    User user0_ 
                left outer join
                    Admin user0_1_ 
                        on user0_.id=user0_1_.userId 
                left outer join
                    Member user0_2_ 
                        on user0_.id=user0_2_.userId 
                where
                    user0_.id=?
                    
            多态性读取成功:study.t3.Admin@1f9407e
            
            Hibernate: 
                alter table Admin 
                   drop 
                   foreign key FKjoav33p64suikub3369fpajy4
                   
            Hibernate: 
                alter table Member 
                   drop 
                   foreign key FKnj6wlxlj0cc3993su1qaykn42
                   
            Hibernate: 
                drop table if exists Admin
                
            Hibernate: 
                drop table if exists Member
                
            Hibernate: 
                drop table if exists User
         */
    }

    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml", this.getClass());
        SessionFactory factory = null;
        try {
            factory = (SessionFactory) context.getBean("sessionFactory");
            
            // 多态性添加
            boolean success = true;
            Session session = null;
            Long id = null;
            try {
                session = factory.openSession();
                success = false;
                session.beginTransaction();
                User user = new Admin();
                user.setLoginName("loginName");
                user.setLoginPass("loginPass");
                ((Admin)user).setRole("role");
                session.save(user);
                session.getTransaction().commit();
                id = user.getId();
                success = true;
            } finally {
                if(session != null){
                    if(!success)
                        session.getTransaction().rollback();
                    session.close();
                    session = null;
                }
            }

            // 多态性读取
            if(success){
                try {
                    session = factory.openSession();
                    session.beginTransaction();
                    success = false;
                    User user = session.load(User.class, id);
                    System.out.println("多态性读取成功:" + user);
                    session.getTransaction().commit();
                    success = true;
                } finally {
                    if(session != null){
                        if(!success)
                            session.getTransaction().rollback();
                        session.close();
                        session = null;
                    }
                }
            }
        } finally {
            if(factory != null){
                factory.close();
                factory = null;
            }
        }
    }
}

 

示例4:继承注解@Inheritance,继承策略InheritanceType.TABLE_PER_CLASS。

User.java

@Entity
@Table
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class User {
    //---------------------------------------------------------------
    // Field
    //---------------------------------------------------------------
    
    @Id
    @Column(name = "id")
    // 不能使用 GenerationType.IDENTITY,可以使用AUTO,或其它。
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator="genId")
    @TableGenerator(
            name = "genId",
            table="GeneratorId",
            pkColumnName="genName",
            valueColumnName="genValue",
            pkColumnValue="nextUserId",
            allocationSize=1
    )
    private Long id;
    
    @Column(name = "loginName",
            length = 20,
            unique = true,
            nullable = false,  
            updatable = false)
    private String loginName;
    
    @Column(name = "loginPass",
            length = 20,
            nullable = false)
    private String loginPass;
    
    //---------------------------------------------------------------
    // Method
    //---------------------------------------------------------------
    
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
    
    public String getLoginName() {
        return loginName;
    }

    public void setLoginName(String loginName) {
        this.loginName = loginName;
    }

    public String getLoginPass() {
        return loginPass;
    }

    public void setLoginPass(String loginPass) {
        this.loginPass = loginPass;
    }
}

Admin.java

@Entity
@Table
public class Admin extends User {
    @Column(name = "role", length = 20, nullable = false)
    private String role;

    public String getRole() {
        return role;
    }

    public void setRole(String role) {
        this.role = role;
    }
}

Member.java

@Entity
@Table
public class Member extends User {
    @Column(name = "name", length = 20, nullable = false)
    private String name;

    public String getName() {
        return name;
    }

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

Test.java

public class Test {
    public static void main(String[] params){
        // 继承注解:@Inheritance
        // 继承策略:InheritanceType.TABLE_PER_CLASS
        // 公共属性独立表,独立属性独立表
        new Test().test();
        /*
            Hibernate: 
                drop table if exists Admin
                
            Hibernate: 
                drop table if exists GeneratorId
                
            Hibernate: 
                drop table if exists Member
                
            Hibernate: 
                drop table if exists User
                
            Hibernate: 
                create table Admin (
                   id bigint not null,
                    loginName varchar(20) not null,
                    loginPass varchar(20) not null,
                    role varchar(20) not null,
                    primary key (id)
                )
                
            Hibernate: 
                create table GeneratorId (
                   genName varchar(255) not null,
                    genValue bigint,
                    primary key (genName)
                )
                
            Hibernate: 
                create table Member (
                   id bigint not null,
                    loginName varchar(20) not null,
                    loginPass varchar(20) not null,
                    name varchar(20) not null,
                    primary key (id)
                )
                
            Hibernate: 
                create table User (
                   id bigint not null,
                    loginName varchar(20) not null,
                    loginPass varchar(20) not null,
                    primary key (id)
                )
                
            Hibernate: 
                alter table Admin 
                   add constraint UK_bdsh7mq6s6xad6ohm08u18uxr unique (loginName)
                   
            Hibernate: 
                alter table Member 
                   add constraint UK_jxtse8o1c6l89j39lilw5e2rs unique (loginName)
                   
            Hibernate: 
                alter table User 
                   add constraint UK_5iebj9qwxsnoshbaq6w834t0y unique (loginName)
                   
            Hibernate: 
                select
                    tbl.genValue 
                from
                    GeneratorId tbl 
                where
                    tbl.genName=? for update
                        
            Hibernate: 
                insert 
                into
                    GeneratorId
                    (genName, genValue)  
                values
                    (?,?)
                    
            Hibernate: 
                update
                    GeneratorId 
                set
                    genValue=?  
                where
                    genValue=? 
                    and genName=?
                    
            Hibernate: 
                insert 
                into
                    Admin
                    (loginName, loginPass, role, id) 
                values
                    (?, ?, ?, ?)
                    
            Hibernate: 
                select
                    user0_.id as id1_2_0_,
                    user0_.loginName as loginNam2_2_0_,
                    user0_.loginPass as loginPas3_2_0_,
                    user0_.role as role1_0_0_,
                    user0_.name as name1_1_0_,
                    user0_.clazz_ as clazz_0_ 
                from
                    ( select
                        id,
                        loginName,
                        loginPass,
                        null as role,
                        null as name,
                        0 as clazz_ 
                    from
                        User 
                    union
                    select
                        id,
                        loginName,
                        loginPass,
                        role,
                        null as name,
                        1 as clazz_ 
                    from
                        Admin 
                    union
                    select
                        id,
                        loginName,
                        loginPass,
                        null as role,
                        name,
                        2 as clazz_ 
                    from
                        Member 
                ) user0_ 
            where
                user0_.id=?
                
            多态性读取成功:study.t4.Admin@12bf0e2
            
            Hibernate: 
                drop table if exists Admin
                
            Hibernate: 
                drop table if exists GeneratorId
                
            Hibernate: 
                drop table if exists Member
                
            Hibernate: 
                drop table if exists User
         */
    }

    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml", this.getClass());
        SessionFactory factory = null;
        try {
            factory = (SessionFactory) context.getBean("sessionFactory");
            
            // 多态性添加
            boolean success = true;
            Session session = null;
            Long id = null;
            try {
                session = factory.openSession();
                success = false;
                session.beginTransaction();
                User user = new Admin();
                user.setLoginName("loginName");
                user.setLoginPass("loginPass");
                ((Admin)user).setRole("role");
                session.save(user);
                session.getTransaction().commit();
                id = user.getId();
                success = true;
            } finally {
                if(session != null){
                    if(!success)
                        session.getTransaction().rollback();
                    session.close();
                    session = null;
                }
            }

            // 多态性读取
            if(success){
                try {
                    session = factory.openSession();
                    session.beginTransaction();
                    success = false;
                    User user = session.load(User.class, id);
                    System.out.println("多态性读取成功:" + user);
                    session.getTransaction().commit();
                    success = true;
                } finally {
                    if(session != null){
                        if(!success)
                            session.getTransaction().rollback();
                        session.close();
                        session = null;
                    }
                }
            }
        } finally {
            if(factory != null){
                factory.close();
                factory = null;
            }
        }
    }
}

 

posted @ 2017-01-22 22:45  突破渴望  阅读(6662)  评论(0编辑  收藏  举报