MySQL数据库中char和vchar区别
比如存储"name"字符串
char(5):['n','a','m','e',''];
vchar(5):['n','a','m','e'];可变长度
数据库中表关系:一对一;一对多、多对一;多对多
如何实现数据库中的表关系?
一对多的表关系在数据库中如何实现?使用外键约束。我们习惯把一的一方称为主表,把多的一方称为从表。
什么是外键?从表中有一列,该列的取值除了null之外,只能来源于主表的主键。(默认情况下,外键字段的值是可以重复的)
多对多的表关系在数据库中如何实现?使用中间表。
中间表中只有两个外键,引用两个多对多表的主键,不能有其他字段信息,至于中间表的主键,应该采用联合主键。
任何一个多方的表和中间表去比较,都是一对多的关系。
一对一的表关系在数据库中如何实现?有两种:
第一种,建立外键。使用外键约束,唯一约束、非空约束,从而实现了一对一。
第二种,使用主键。让其中一张表既是主键,又是外键。
如何确立数据库中的两张表关系?找外键
学习多表映射配置要遵循的步骤
第一步:确立两张表之间的关系
第二步:在数据库中实现两张表之间的关系建立,一是主表,多是从表,在从表配置外键
第三步:在实体类中描述出两个实体之间的关系,主表的实体类应该包含从表实体类的集合引用,从表的实体类应该包含主表实体类的对象引用(构造方法和toString方法不要写关联表的集合或对象的引用)
第四步:在映射配置文件中建立两个实体和两张表之间的关系
Cla.java
private Integer claId;
private String claName;
private Set<Stu> stu = new HashSet<Stu>(0);
Cla.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="org.haiwen.entity.Cla" table="cla">
<id name="claId" column="cla_id" >
<generator class="native" />
</id>
<property name="claName" type="java.lang.String" column="cla_name" />
<!-- 一对多关系映射:主表实体的映射配置
标签:set
作用:用于配置set集合属性
属性:name,指定实体类中引用从表set集合的属性名称.
table,指定从表的名称,在一对多配置时可以不写.
标签:key
作用:用于映射外键关系
属性:column,指定外键字段名称
标签:one-to-maney
作用:用于建立一对多的映射配置
属性:class,用于指定从表实体的名称 -->
<set name="stu" table="stu" inverse="true" cascade="save-update">
<key column="cla_id"></key>
<one-to-many class="org.haiwen.entity.Stu"/>
</set>
</class>
</hibernate-mapping>
Stu.java
private Integer stuId;
private String stuName;
private Cla cla;
Stu.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="org.haiwen.entity.Stu" table="stu">
<id name="stuId" column="stu_id" >
<generator class="native" />
</id>
<property name="stuName" type="java.lang.String" column="stu_name" />
<!-- 多对一关系映射:从表实体的映射配置
标签:many-to-one
作用:建立多对一的映射
属性:name,从表实体中引用主表实体对象引用的名称
class,指定属性所对应的实体类名称
column,指定从表中外键字段的名称 -->
<many-to-one name="cla" class="org.haiwen.entity.Cla" column="cla_id"></many-to-one>
</class>
</hibernate-mapping>
hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/hibernate</property>
<property name="connection.username">root</property>
<property name="connection.password">root</property>
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.hbm2dll.auto">update</property>
<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<property name="hibernate.current_session_context_class">thread</property>
<mapping resource="org/haiwen/entity/Cla.hbm.xml" />
<mapping resource="org/haiwen/entity/Stu.hbm.xml" />
</session-factory>
</hibernate-configuration>
HibernateUtils.java
public class HibernateUtils {
static Configuration cfg;
static SessionFactory factory = null;
static {
try {
cfg = new Configuration();
cfg.configure();
factory = cfg.buildSessionFactory();
} catch (ExceptionInInitializerError e) {
throw new ExceptionInInitializerError("初始化SessionFactory失败,请检查配置文件");
}
}
public static Session getCurrentSession() {
return factory.getCurrentSession();// 每次使用该方法从当前线程上获取一个session,只有配置了session和线程绑定之后才能使用此方法,否则返回null
}
}
一对多保存
/**
*创建一个班级和一个学生,建立班级和学生的双向关联关系
*使用符合原则的保存:先保存主表实体,再保存从表实体
*此时保存会有问题:我们保存两个实体,应该只有两条insert语句,执行结果却是多了一条update语句
*解决方法:在班级执行操作的时候,放弃维护关联关系的权利
*配置的方式:在Cla的映射配置文件中的set标签上使用inverse属性
*inverse含义:是否放弃维护关联关系的权利
*true:放弃
*false:不放弃(默认值)
*/
public void save() {
// 1.创建一个班级
Cla cla = new Cla();
cla.setClaName("武将");
// 2.创建一个学生
Stu stu = new Stu();
stu.setStuName("关羽");
// 3.建立班级和学生的关联关系(双向)
stu.setCla(cla);
cla.getStu().add(stu);
Session session = HibernateUtils.getCurrentSession();
session.getTransaction().begin();
// 4.保存规则,先保存主表实体,在保存从表实体
session.save(cla);
session.save(stu);
session.getTransaction().commit();
}
级联保存
/**
* 级联保存:只写一个方法同时保存主表实体和从表实体
* 配置方式:在Cla的映射配置文件中的set标签上使用cascade属性,此时使用session.save(c);
* 也可以写在Stu的映射配置文件中的many-to-one标签上,此时使用session.save(s);
* cascade属性:配置级联操作
* save-update:级联保存更新
*/
public void save() {
Cla cla = new Cla();
cla.setClaName("武将");
Stu stu = new Stu();
stu.setStuName("关羽");
stu.setCla(cla);
cla.getStu().add(stu);
Session session = HibernateUtils.getCurrentSession();
session.getTransaction().begin();
session.save(cla);
session.getTransaction().commit();
}
级联更新
/**
* 同时做两件事,先将stu实体保存,再更新cla数据库
*/
public void update() {
Session session = HibernateUtils.getCurrentSession();
session.getTransaction().begin();
Cla cla = (Cla) session.get(Cla.class, 1);
cla.setClaName("武将");
Stu stu = new Stu();
stu.setStuName("张飞");
stu.setCla(cla);
cla.getStu().add(stu);
session.update(cla);
session.getTransaction().commit();
}
级联删除
/**
* 删除主表时,同时删除关联从表
* 当cascade="delete"属性设置在主表时
* 删除从表数据就是单表删除
* 删除主表数据时,判断
* 没有从表数据引用,单表删除
* 有从表数据引用,hibernate会把从表中的外键设置为null,然后删除从表数据,再删除主表数据
* 如果外键字段有非空约束,则hibernate不能跟新外键字段为null,会报错
* 当cascade="delete"属性设置在从表时,反之亦然,可同时设置cascade="save-update,delete"
* 级联删除要慎用
*/
public void delete() {
Session session = HibernateUtils.getCurrentSession();
session.getTransaction().begin();
Cla cla = (Cla) session.get(Cla.class, 1);
session.delete(cla);
session.getTransaction().commit();
}
对象导航查询
一对多
/**
* 一对多,根据一的一方查询多的一方时,需要使用延迟加载(默认配置即可)
*/
public void oneToMany() {
Session session = HibernateUtils.getCurrentSession();
session.getTransaction().begin();
Cla cla = (Cla) session.get(Cla.class, 1);
System.out.println(cla.getStu());
session.getTransaction().commit();
}
多对一
/**
* 多对一,根据多的一方查询一的一方时,不需要使用延迟加载,而是使用立即加载,需要配置
* 配置:从表的映射配置文件,在many-to-one标签上使用lazy属性.
* 取值:false,使用立即加载
* proxy,看load方法是延迟加载还是立即加载
*/
public void manyToOne() {
Session session = HibernateUtils.getCurrentSession();
session.getTransaction().begin();
Stu stu = (Stu) session.get(Stu.class, 1);
System.out.println(stu.getCla());
session.getTransaction().commit();
}
class标签的lazy:负责load方法是否是延迟加载。
set标签的lazy:负责查询关联的集合对象是否是延迟加载。
many-to-one的lazy:负责查询关联的主表实体是否是立即加载。
<many-to-one> 属性fetch:抓取策略,表示以什么方式进行关联关系对象的加载
- select:以单独一条select语句查询关联关系对象,支持lazy
- join:以连接查询的方式查询关联关系对象,不支持lazy
<many-to-one> 属性lazy:关联级别的延迟加载
- false:表示不延迟
- proxy:表示延迟加载(关联级别最好使用延迟加载 )
<set> 属性inverse: 表示是否放弃对于关联关系的控制权
- true:放弃控制权
- false:不放弃控制权
<set> 属性cascade:级联策略,表示当操作当前对象时,以什么方式级联操作关联关系对象
- save:当保存当前对象时,级联保存关联关系对象
- save-update:当保存或更新当前对象时,级联保存或更新关联关系对象
- delete:当删除先前对象时,级联删除关联关系对象
- all:当操作当前对象时,级联操作关联关系对象
Hibernate关联关系映射
- 不管关系多复杂,在数据库端只有一个字段:外键
- 不管关系多复杂,在java程序中无非就是一个对象和一个集合的事
- XXX-to-one,只要关联一个关系对象,在本类中就是一个对象
- XXX-to-many,只要关联多个关系对象,在本类中就是一个集合