`
oham_一1一
  • 浏览: 51322 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

Hibernate使用——实体映射的几种策略

阅读更多

环境:DB——MySQL,hibernate4.1.4

 

面向设计的粒度细分

通过对象细化,实现更加清晰的系统逻辑划分——情景:重新规划已有系统,通过case分析得出新的类设计,但相应地数据库的表的ER不希望改变。现有一表:t_person

create table t_person(
  id int(11) not null auto_increment,
  name varchar(80) not null default '',
  address varchar(100),
  tel varchar(12),
  zipcode varchar(10),
  primary key (id)
);

 

 原来的TPerson.java如下:

package learnHibernate.bean;

import java.io.Serializable;

public class TPerson implements Serializable {
	private static final long serialVersionUID = -7714660203394864063L;
	
	private int id;
	private String name;
	private String address;
	private String tel;
	private String zipcode;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	public String getTel() {
		return tel;
	}
	public void setTel(String tel) {
		this.tel = tel;
	}
	public String getZipcode() {
		return zipcode;
	}
	public void setZipcode(String zipcode) {
		this.zipcode = zipcode;
	}
	
}

 

经过重新规划后,决定将联系方式的信息封装到Contact类当中。

变成如下:由Tperson持有Contact对象

package learnHibernate.bean;

import java.io.Serializable;

public class TPerson implements Serializable {
	private static final long serialVersionUID = -7714660203394864063L;
	
	private int id;
	private String name;
	private Contact contact;
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Contact getContact() {
		return contact;
	}
	public void setContact(Contact contact) {
		this.contact = contact;
	}
}

 

Contact.java:

package learnHibernate.bean;

import java.io.Serializable;

public class Contact implements Serializable {
	private static final long serialVersionUID = 2372937305763736126L;
	
	private String address;
	private String tel;
	private String zipcode;
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	public String getTel() {
		return tel;
	}
	public void setTel(String tel) {
		this.tel = tel;
	}
	public String getZipcode() {
		return zipcode;
	}
	public void setZipcode(String zipcode) {
		this.zipcode = zipcode;
	}
}

 

对于上述,hibernate的hbm.xml映射文件用到了component节点:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
  
<hibernate-mapping package="learnHibernate.bean">
	<class name="TPerson" table="t_person">
		<id name="id" column="id" type="java.lang.Integer">
			<generator class="native"/>
		</id>
		
		<property name="name" column="name" type="java.lang.String"/>
		
		<component name="contact" class="learnHibernate.bean.Contact">
			<property name="address" column="address" type="java.lang.String"/>
			<property name="tel" column="tel" type="java.lang.String"/>
			<property name="zipcode" column="zipcode" type="java.lang.String"/>
		</component>
	</class>
	
</hibernate-mapping> 

上述就ORM这一方面,与普通的类表映射没有太大区别,只是体现在设计上面的改进。

 

 

面向性能的粒度细分

1.情景:现在有一表T_user,其中有一粗大无比的字段resume:

CREATE TABLE  t_user (
  id int(11) NOT NULL auto_increment,
  name varchar(80) NOT NULL default '',
  resume longtext,
  PRIMARY KEY  (id)
);

 有时候,我们只想列出user的name列表,此时若也把resume这个字段一并查出,这无疑造成不必要的性能浪费。。。此时可以用延迟加载的方式解决,此处不赘述。介绍另一种:

 

在继承层次上对粒度进一步细化:

原来的TUser.java:

package learnHibernate.bean;  
  
import java.io.Serializable;  
  
public class TUser implements Serializable{  
    private static final long serialVersionUID = -2983670695642662371L;  
      
    private int id;  
    private String name;  
    private String resume;  
      
    public int getId() {  
        return id;  
    }  
    public void setId(int id) {  
        this.id = id;  
    }  
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
    public String getResume() {  
              return resume;  
    }  
    public void setResume(String resume) {  
          this.resume = resume;  
    }  
} 

 

现在将resume从Tuser.java中抽出,移到子类TUserInfo.java当中:

package learnHibernate.bean;


public class TuserInfo extends TUser {
	private static final long serialVersionUID = -7362075358002914585L;
	
	private String resume;
	
	public String getResume() {
		return resume;
	}
	public void setResume(String resume) {
		this.resume = resume;
	}
}

 

对应的映射文件如下:

TUser.hbm.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
  
<hibernate-mapping package="learnHibernate.bean">
	<class name="TUser" table="t_user">
		<id name="id" column="id" type="java.lang.Integer">
			<generator class="native"/>
		</id>
		
		<property name="name" column="name" type="java.lang.String"/>
	</class>
	
</hibernate-mapping>

 

TUserInfo.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
  
<hibernate-mapping package="learnHibernate.bean">
	<class name="TUserInfo" table="t_user" polymorphism="explicit">
		<id name="id" column="id" type="java.lang.Integer">
			<generator class="native"/>
		</id>
		
		<property name="name" column="name" type="java.lang.String"/>
		
		<property name="resume" column="resume" type="java.lang.String"/>
	</class>
	
</hibernate-mapping>

 

其中polymorphism="explicit"意思是声明一个显式的多态关系,声明为显式多态的类只有在明确指定类名的时候才会返回此类实例: 

 

String hql1 = "From TUser where name='Oham'";
		TUser tu = (TUser)session.createQuery(hql1).list().get(0);
		System.out.println("=============");
		
		String hql2 = "From TUserInfo where name='Oham'";
		TUserInfo ti = (TUserInfo)session.createQuery(hql2).list().get(0);

 

 

若执行类似上述的代码,看后台log出的SQL:

 

Hibernate: 
    select
        tuser0_.id as id0_,
        tuser0_.name as name0_ 
    from
        t_user tuser0_ 
    where
        tuser0_.name='Oham'
=============
Hibernate: 
    select
        tuserinfo0_.id as id0_,
        tuserinfo0_.name as name0_,
        tuserinfo0_.resume as resume0_ 
    from
        t_user tuserinfo0_ 
    where
        tuserinfo0_.name='Oham'

 若执行createQuery("From Object").list(); 则将返回数据库中所有的表记录的数据对象,其中,对应t_user表的记录将以Tuse返回,而不是TUserInfo,也就是说不包含resume字段。

 

 

2.实体层次设计——继承关系是关系型数据与面向对象数据结构之间的主要差异之一,在关系型数据库的基础上,就对象的继承关系进行清晰合理的层次划分。

    Hibernate中支持3种类型的继承形式

    1)Table per concrete class   —— 表与子类之间的独立一对一关系;

    2)Table per subclass   —— 每个子类对应一张子表,并与主类共享主表;

    3)Table per class hierarchy  —— 表与类的一对多关系;

 

 现给出如下的类关系:

TMember.java

package learnHibernate.bean;

import java.io.Serializable;
import java.util.List;

public class TMember implements Serializable{
	private static final long serialVersionUID = -2487367694260008988L;
	
	private int id;
	private String name;
	private List email;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public List getEmail() {
		return email;
	}
	public void setEmail(List email) {
		this.email = email;
	}
}

 

 TOham和TLulu都继承TMember,TOham.java:

package learnHibernate.bean;

public class TOham extends TMember {

	private String meditation;

	public String getMeditation() {
		return meditation;
	}
	public void setMeditation(String meditation) {
		this.meditation = meditation;
	}
}

 

 TLulu.java:

package learnHibernate.bean;

public class TLulu extends TMember {

	private String sixthSense;

	public String getSixthSense() {
		return sixthSense;
	}

	public void setSixthSense(String sixthSense) {
		this.sixthSense = sixthSense;
	}
}

 

 Table per concrete class   —— 表与子类之间的独立一对一关系:

TOham和TLulu都继承于TMember,所以自然就包含了Tmember的属性了,在Table per concrete class模式当中,每个子类分别对应一个独立的表,表中包含了子类所需的所有字段:

t_oham表:

 

TOham.hbm.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
  
<hibernate-mapping package="learnHibernate.bean">
	<class name="TOham" table="t_oham">
		<id name="id" column="id" type="java.lang.Integer">
			<generator class="native"/>
		</id>
		
		<property name="name" 
				  column="name" 
				  type="java.lang.String"/>
				  
		<property name="email" 
				  column="email" 
				  type="learnHibernate.bean.EmailList" />
				  
		<property name="meditation" 
				  column="meditation" 
				  type="java.lang.String"/>
	</class>
</hibernate-mapping>

 

t_lulu表:

 

TLulu.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
  
<hibernate-mapping package="learnHibernate.bean">
	<class name="TLulu" table="t_lulu">
		<id name="id" column="id" type="java.lang.Integer">
			<generator class="native"/>
		</id>
		
		<property name="name" 
				  column="name" 
				  type="java.lang.String"/>
				  
		<property name="email" 
				  column="email" 
				  type="learnHibernate.bean.EmailList" />
				  
		<property name="sixthSense" 
				  column="sixthsense" 
				  type="java.lang.String"/>
	</class>
</hibernate-mapping>

 
 从上述配置可以看出Table per concrete class 模式的映射方式似乎跟普通的映射并无区别,在hibernate的角度,以多态(polymorphism)来描述TOham,TLulu与TMember的继承关系,TOham,TLulu的映射配置文件没有出现polymorphism属性的定义,也就是说采用了默认的隐式多态模式(polymorphism=“implicit”)。

执行:

String hql = "From TMember";
		List list = session.createQuery(hql).list();

后台 log出的hibernate SQL:

 

Hibernate: 
    select
        tlulu0_.id as id3_,
        tlulu0_.name as name3_,
        tlulu0_.email as email3_,
        tlulu0_.sixthsense as sixthsense3_ 
    from
        t_lulu tlulu0_
Hibernate: 
    select
        toham0_.id as id2_,
        toham0_.name as name2_,
        toham0_.email as email2_,
        toham0_.meditation as meditation2_ 
    from
        t_oham toham0_
Hibernate: 
    select
        tmember0_.id as id1_,
        tmember0_.name as name1_,
        tmember0_.email as email1_ 
    from
        t_member tmember0_

 Hibernate会在当前环境中查找所有polymorphism=“implicit”的子类,并返回子类所对应的所有表的记录。

 

可以看出,对象的继承关系在持久层得到了体现,不过此种映射方式也存在着一些局限,如t_oham,t_lulu的父字段必须保持一致,若父类TMember发生变动,子类必须同时修改。有时候我们会根据一个name字段进行查询,此时就可能要对每个子表查询后汇总,于是我们希望有的大表包含所有可能出现的字段。借助这种情形,下面介绍Table per subclass   —— 每个子类对应一张子表,并与主类共享主表 和 Table per class hierarchy  —— 表与类的一对多关系

 

Table per subclass   —— 每个子类对应一张子表

接着上述的例子由于父类TMember发生变动,子类TOham,TLulu必须同时修改,所以重新设计表ER,让t_oham和t_lulu字表只包含子类所扩展的属性,同时子表与父表通过外键相关联:

 

TMember.hbm.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
  
<hibernate-mapping package="learnHibernate.bean">
	<class name="TMember" table="t_member">
		<id name="id" column="id" type="java.lang.Integer">
			<generator class="native"/>
		</id>
		
		<property name="name" column="name" type="java.lang.String"/>
		<property name="email" column="email" type="learnHibernate.bean.EmailList" />
		
		<joined-subclass name="TOham" table="t_oham">
			<key column="id"/>
			<property name="meditation" column="meditation"/>
		</joined-subclass>
		
		<joined-subclass name="TLulu" table="t_lulu">
			<key column="id"></key>
			<property name="sixthSense" column="sixthsense"/>
		</joined-subclass>
	</class>
	
</hibernate-mapping>

 通过joined-subclass节点在父类映射文件中对子类TOham, TLulu进行配置,joined-subclass节点与class节点类似,且joined-subclass节点可以嵌套。

 

执行:

 

TOham o = new TOham();
		o.setName("oham2");
		o.setMeditation("Civilization Rise");
		session.save(o);
		
		TOham o2 = new TOham();
		o2.setName("oham3");
		session.save(o2);
		
		TLulu l = new TLulu();
		l.setName("Lulu2");
		l.setSixthSense("Dancing soul");
		session.save(l);

 

后台log:

 

Hibernate: 
    insert 
    into
        t_member
        (name, email) 
    values
        (?, ?)
Set method executed
Hibernate: 
    insert 
    into
        t_oham
        (meditation, id) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_member
        (name, email) 
    values
        (?, ?)
Set method executed
Hibernate: 
    insert 
    into
        t_oham
        (meditation, id) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_member
        (name, email) 
    values
        (?, ?)
Set method executed
Hibernate: 
    insert 
    into
        t_lulu
        (sixthsense, id) 
    values
        (?, ?)

 

再执行:

String hql = "From TMember";
		session.createQuery(hql).list();

 后台log:

Hibernate: 
    select
        tmember0_.id as id1_,
        tmember0_.name as name1_,
        tmember0_.email as email1_,
        tmember0_1_.meditation as meditation2_,
        tmember0_2_.sixthsense as sixthsense3_,
        case 
            when tmember0_1_.id is not null then 1 
            when tmember0_2_.id is not null then 2 
            when tmember0_.id is not null then 0 
        end as clazz_ 
    from
        t_member tmember0_ 
    left outer join
        t_oham tmember0_1_ 
            on tmember0_.id=tmember0_1_.id 
    left outer join
        t_lulu tmember0_2_ 
            on tmember0_.id=tmember0_2_.id

 

相对于Table per concrete class,Table per subclass 带来了更加清晰的数据逻辑划分,不过跟Table per concrete class类似,当遇到多表操作的时候,系统性能都不太高,对于高并发的数据存取都不利;以此来介绍Table per class hierarchy。

 

实际开发中,通过冗余字段表达同类型数据可能是我们在绝大多数情况下的选择。对于上述的示例,我们可以通过一个包含所有子类字段的t_member表存储所有信息。

对于上述例子,重建t_member表:

这样,数据的存取都能通过一条简单的sql即可完成。在简易和性能两方面考量都能得到一个较为满意的结果。但需要重新设计映射以体现不同子类的差异。

 

此时再对t_member表添加一个字段来标识不同的子类:Category。

Category 为1 是代表TOham记录

Category 为2 是代表TLulu记录。


 

为了hibernate能自动根据category节点识别对应的子类class类型,需要在配置文件中进行配置,而discriminator节点,则定义了这种配置关系。

TMember.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
  
<hibernate-mapping package="learnHibernate.bean">
	<class name="TMember" table="t_member">
	
		<id name="id" 
			column="id" 
			type="java.lang.Integer">
			<generator class="native"/>
		</id>
		
		<!-- 通过discriminator节点,声明了用于子类辨别标识的表字段名 -->
		<discriminator column="category" 
					   type="java.lang.String"/>
		
		<property name="name" 
				  column="name" 
				  type="java.lang.String"/>
		
		<property name="email" 
				  column="email" 
				  type="learnHibernate.bean.EmailList" />
		
		<!-- 辨别标识的字段值为1时,对应子类为TOham -->
		<subclass name="TOham" 
			 	  discriminator-value="1">
			<property name="meditation" 
					  column="meditation"/>	
		</subclass>
			
		<!-- 辨别标识的字段值为2时,对应子类为TLulu -->
		<subclass name="TLulu" 
				  discriminator-value="2">
			<property name="sixthSense" 
					  column="sixthsense"/>	
	    </subclass>
		
	</class>
</hibernate-mapping>

 如此,运行期hibernate在读取t_member表数据时,会根据指定的辨别标识进行判断,如果记录的category为1,则映射到TOham,为2映射到TLulu。

 

执行:

String hql1 = "From TOham";
		String hql2 = "From TLulu";
		
		session.createQuery(hql1).list();
		session.createQuery(hql2).list();

 后台log:

Hibernate: 
    select
        toham0_.id as id1_,
        toham0_.name as name1_,
        toham0_.email as email1_,
        toham0_.meditation as meditation1_ 
    from
        t_member toham0_ 
    where
        toham0_.category='1'
Hibernate: 
    select
        tlulu0_.id as id1_,
        tlulu0_.name as name1_,
        tlulu0_.email as email1_,
        tlulu0_.sixthsense as sixthsense1_ 
    from
        t_member tlulu0_ 
    where
        tlulu0_.category='2'

 注意一点:discriminator 节点的type貌似不能指定为除String以外的类型,在下试过,说:

                          Caused by: org.hibernate.MappingException: Could not format discriminator value to SQL string。

 

 

 

 

 

 

 

 

 

 

 


 

 

 

 

 

  • 大小: 11.9 KB
  • 大小: 10.3 KB
  • 大小: 10.5 KB
  • 大小: 4.5 KB
  • 大小: 4.3 KB
分享到:
评论

相关推荐

    Hibernate教程09_关系映射之组件映射

    源码可能包含了`Employee`、`Address`以及其他相关类,以及对应的配置文件,如`hibernate.cfg.xml`,用以配置Hibernate的会话工厂和实体映射。 在配置文件中,组件映射不会像实体那样定义一个单独的表,而是将组件...

    Hibernate数据关联映射与继承策略

    在 Hibernate 中,为了处理对象模型中的继承关系,提供了以下几种继承策略: 1. **单表继承(Single Table Inheritance)**:所有子类共享同一张数据库表,使用一个标识字段来区分不同的子类实例。优点是简单,但...

    Hibernate_Annotation关联映射

    Hibernate Annotation几种关联映射 一对一(One-To-One) ...以上是整理的一点简单的几种映射,可参考EJB3.pdf中P111——P131,hibernate_annotation.pdf 第二章 在这里没有具体的例子,有很多内容还需要仔细查看文档。

    hibernate实体设计

    本文通过对给定部分内容的分析,介绍了Hibernate实体层设计的基本原理和技巧,包括实体类的定义、映射文件的设计以及单一表设计模式的优缺点。通过学习这些内容,开发者可以更好地掌握Hibernate的使用方法,从而提高...

    hibernate使用中与各种数据库字段类型对应类型训练

    首先,我们要理解Hibernate的核心概念——对象关系映射(ORM)。ORM允许我们将数据库表结构映射到Java类,每个表对应一个类,表中的字段对应类的属性。这种映射是通过Hibernate的配置文件(如.hbm.xml)或者使用注解...

    Struts2与Hibernate3的集成开发案例——网上书店

    Struts2和Hibernate3是两种在Java EE开发中广泛应用的开源框架。Struts2作为MVC(模型-视图-控制器)架构的实现,主要用于处理Web应用中的业务逻辑和控制流程,而Hibernate3则是一个对象关系映射(ORM)工具,简化了...

    Hibernate快速入门

    在“Hibernate快速入门”中,我们将深入理解Hibernate的核心概念,包括实体映射、对象关系映射(ORM)、Session管理以及查询语言。 首先,Hibernate通过ORM机制将Java对象与数据库表进行映射,使得我们可以在Java...

    Hibernate关联映射-one to one单向外键关联

    本话题主要探讨的是Hibernate中的一种关联映射方式——一对一(One-to-One)单向外键关联。这种关联模式通常用于两个实体之间存在唯一对应的关系,例如一个用户对应一个唯一的账户。 在Hibernate中,一对一关联可以...

    hibernate相关jar包

    Hibernate是一个开源的对象关系映射(ORM)框架,它允许开发者使用面向对象的编程方式来操作数据库,极大地简化了Java应用程序中的数据持久化过程。在Java开发中,Hibernate扮演着一个重要的角色,它通过提供一种...

    hibernate课程笔录

    Hibernate使用XML或注解配置来定义这些实体与数据库表之间的映射关系,这被称为Hibernate配置文件或映射文件。 课程内容可能包括以下几个关键知识点: 1. **安装与配置**: 学习如何将Hibernate库添加到项目中,...

    day36 07-Hibernate抓取策略:many-to-one上的抓取策略

    但这种方式可能不适用于所有场景,特别是在需要一次性获取所有关联数据时,可以使用以下几种抓取策略: 1. **FetchType.EAGER**:设置关联为预加载,意味着当主实体加载时,其关联的对象也会一起加载。这减少了...

    Hibernate Annotation笔记

    使用Hibernate Annotation时,需要在实体类中使用特定的注解来定义与数据库表之间的映射规则。以下是几种常用的注解: - **@Entity**:标记类为Hibernate的实体类。 - **@Table**:指定实体类所对应的数据库表名...

    Hibernate学习笔记

    实体映射是Hibernate的核心部分,通过Java注解或XML文件(如`hibernate-mapping.xml`)将Java类与数据库表关联。例如,`@Entity`标识一个类为实体,`@Table`指定对应的数据库表,`@Id`标记主键,`@GeneratedValue`...

    14 继承(一)(整个继承树映射到一张表)

    在Hibernate中,当一个类继承体系映射到数据库时,有几种策略可以采用。其中一种是单表继承策略,即"整个继承树映射到一张表"。这种策略意味着所有子类的对象数据都将存储在同一个数据库表中,通过一个特定的字段来...

    hibernate doc 中文版

    - 详细解释如何使用XML映射文件或注解来定义实体类与数据库表之间的映射关系。 - **Entity:** - 定义映射的基本单位——Entity。 - **Identifiers:** - 主键的生成策略和映射方式。 - **Optimistic locking ...

    hibernate资源

    2. **表映射(Mapping)**:Hibernate使用XML文件(hibernate.cfg.xml)或注解来定义实体类与数据库表的映射关系。XML配置文件中包含了数据源、SessionFactory等配置,而实体类的注解则用于指定字段与数据库列的对应...

    hibernate实现动态表查询的多种解决方案

    1. **命名策略(NamingStrategy)**:Hibernate默认使用一种命名策略来转换实体类属性名到数据库列名。如果希望自定义这种映射规则,可以通过实现`NamingStrategy`接口来自定义命名策略。 2. **拦截器(Interceptor...

    最经典的hibernate教程_从入门到精通_第四篇

    2. **实体类与数据表映射**:理解Hibernate的核心元素——实体类,如何通过注解或XML配置文件将实体类与数据库表进行映射,包括@Id、@Column等注解的使用。 3. **持久化操作**:掌握基本的CRUD(创建、读取、更新、...

Global site tag (gtag.js) - Google Analytics