Hibernate笔记一
背景
jdbc的优缺点
A:直接操作底层,提供了简单,便捷的访问数据库方法,跨平台比较强,灵活,可以写很多赋值的SQL语句;是最底层的数据库操作,所以效率比较高,Sql语句可以自己选择写,采用效率最高的
B:因为Java是面向对象的,JDBC没有做到使数据能够面向对象的编程,使程序员的思考仍然停留在SQL语句上面,操作繁琐,
很多代码需要重复写好多次,如果遇到批量操作,繁琐与数据库的交互,容易造成效率的下降
代码结构比较繁琐,面向纯sql语句的编程,面向过程的编程,对于查询而言,只要查询数据库的一张表,必须有如下的编码:Jdbc技术没有做到数据缓存
因为事务是自动开启的,所以可能存在安全性的隐患
JDBC从程序操作可以封装一些什么内容:
JDBC从程序操作不可以封装一些什么内容:
Hibernate
2.1:优点:
是一个ormapping框架,是一个操作数据库的框架
面向对象编程的
代码编程比较简单
Hibernate做到了数据缓存
Hibernate用得场合最多的情况是企业中的中小型项目
2.2:缺点:
该框架程序员是没有办法干预sql语句的生成的
如果一个项目中,对sql语句的优化的要求比较高,这个时候不能用hibernate来做
表之间的关系很复杂的情况下,不能用hibernate来操作
如果一张表的数据超过了千万级别也不适合用hibernate来做
分拣:ETL数据抽取
2.3持久化类:
2.4:映射文件:
数据库有多少张表,至少应该有多少个映射文件。
2.5:配置文件:
完成数据库的链接信息的填写
一般有一个
Hibernate入门操作
创建一个java project
1.准备jar包
2.创建hibernate的配置文件:
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<!--
一个session-factory代表一个数据库
-->
<session-factory>
<!--
链接数据库的用户名
-->
<property name="connection.username">root</property>
<!--
链接数据库的密码
-->
<property name="connection.password">root</property>
<!--
链接数据库的驱动
-->
<property name="connection.driver_class">
com.mysql.jdbc.Driver
</property>
<!--
链接数据库的url
-->
<property name="connection.url">
jdbc:mysql://localhost:3306/itheima09_hibernate
</property>
<!--
方言
告诉hibernate用什么样的数据库
-->
<property name="dialect">
org.hibernate.dialect.MySQLDialect
</property>
<!--
validate 加载hibernate时,验证数据库的结构
update 加载hibernate时,检查数据库,如果表不存在,则创建,如果存在,则更新
create 每次加载hiberante,都会创建表
create-drop 每次加载hiberante,创建,卸载hiberante时,销毁
-->
<property name="hbm2ddl.auto">update</property>
<!--
显示sql语句
-->
<property name="show_sql">true</property>
<!--
格式化sql语句
-->
<property name="format_sql">true</property>
<!--
加载映射文件
-->
<mapping resource="com/itheima09/hibernate/domain/Person.hbm.xml" />
</session-factory>
</hibernate-configuration>
Hibernate.cfg.xml
3.创建hibernate的持久化类:
Customer.java
说明:持久化类中必须有一个默认的构造器
4.创建映射文件:
Customer.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>
<!--
描述一个持久化类
name属性为持久化类的全名
table 该持久化类对应的表名 默认情况下为类名
catalog 为数据库的名称
-->
<class name="com.itheima09.hibernate.domain.Person" table="pereson">
<!--
id对应表中的主键
name为持久化类中属性的名称
length 为对应数据库表中相应字段的长度
column 属性的名称对应的表的字段名称 不写则默认和属性的名称一致
-->
<id name="pid" length="5" type="java.lang.Long" column="pid">
<!--
主键的生成器
-->
<generator class="increment"></generator>
</id>
<property name="name" column="name" type="java.lang.String" length="20">
</property>
<property name="description" column="description" type="java.lang.String" length="50">
</property>
</class>
</hibernate-mapping>
Person.hbm.xml
说明:
从图中可以看出,该映射文件完成了从类到表、类中的属性到表中的字段的对应关系。
操作数据库:
import java.util.List; import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.impl.SessionFactoryImpl;
import org.junit.Test; import com.itheima09.hibernate.domain.Person;
import com.itheima09.hibernate.utils.HibernateUtils; public class PersonDao extends HibernateUtils{
@Test
public void savePerson(){
//创建配置文件对象
Configuration configuration = new Configuration();
//加载配置文件 1、该配置文件必须放在根目录下 2、名称必须为hibernate.cfg.xml
configuration.configure();
//有一个参数,该参数为hibernate配置文件的路径
//configuration.configure("");
//创建sessionFactory
SessionFactory sessionFactory = configuration.buildSessionFactory();
//打开一个session
Session session = sessionFactory.openSession();
//创建一个事务
Transaction transaction = session.beginTransaction();
Person person = new Person("");
person.setName("王二麻子");
person.setDescription("霸气");
//利用session把person对象保存
session.save(person);
//事务提交
transaction.commit();
//session关闭
session.close();
} @Test
public void updatePerson(){
//加载配置文件
Configuration configuration = new Configuration();
configuration.configure();
SessionFactory factory = configuration.buildSessionFactory();
Session session = factory.openSession();
Transaction transaction = session.beginTransaction();
/**
* 根据主键查询数据库表中的一行记录
* 第一个参数为持久化类的class形式
* 第二个参数为对象的序列化,能接受基本类型的包装类、String
*/
Person person = (Person)session.get(Person.class, 1L);
person.setDescription("就是牛");
session.update(person);
transaction.commit();//事务的提交
session.close();
} @Test
public void testQueryPerson(){
Session session = sessionFactory.openSession();
//from后面跟的是持久化类名,不是表名
List<Person> personList = session.createQuery("from Person").list();
System.out.println(personList.size());
} @Test
public void testDeletePerson(){
/**
* 1、从数据库中把pid为1的数据提取出来
* 2、删除
*/
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
//把pid为1的持久化对象提取出来
Person person = (Person)session.get(Person.class,1L);
session.delete(person);
transaction.commit();
session.close();
} @Test
public void testSessionFactory(){ }
}
Dao.java
Hibernate的流程
说明:
1、 crud操作是由session来完成的
2、 在hibernate中事务不是自动提交的
入门例子详细解析
Configuration类
利用该类加载了hibernate的配置文件
sessionFactory类
1、 hibernate配置文件的信息、持久化类的信息、映射文件的信息全部在该类中
2、 sessionFactory对象有且只有一个
3、 生命周期是整个hibernate实例
4、 sessionFactory本身就是线程安全的
5、 二级缓存在sessionFactory中存放
6、 sessionFactory和数据库的链接没有直接的关系
session类
1、 crud操作由session来完成的
2、 一个session代表数据库的一个链接
内部执行流程
Hibernate的反向工程
工具数据库表生成Hibernate工程(简单粗暴)
第一步
第二步
第三步
第四步
以上四步就是一个工程变成hibernate工程
第五步
该模式是myeclipse链接数据库的模式
第六步
第七步
在该模式下创建了一个链接
第八步
第九步
第十步
第十一步
第十二步
上述的步骤完成以后,会看到如下的结构:
Hibernate中的类型
在hibernate中有两种类型:java type,hibernate type
Java type
Hibernate内部直接提供了java类型到数据库的对照表
说明:用java类型可以直接完成从java类型到数据库类型的映射
Hibernate类型
从上面可以看出如果选择hibernate类型,需要查找该hibernate类型对应的java类型,从而再找到数据库类型,所以java类型效率比较高
主键的产生器
Increment:
查找主键的最大值,在最大值的基础上加1
效率比较低
Assigned
注意:由程序手动赋值
Identity
支持主键自动增长
Uuid
持久化类中的属性必须是String类型
Native
Hibernate会根据数据库的不同,选择合适的主键的生成策略
Sequence
是oracle内部特有的内容,相当于uuid,所以是字符串类型
对象的状态
应用场景
如果一个班的所有的学生要把考试的成绩同步到数据库的表中,如果每一个学生和数据库交互一次,那么如果有60个学生,需要跟数据库交互60次,这样效率比较低
对象的状态的值
1.临时状态
2.持久化状态
3.脱管状态
案例1
说明:
1.临时状态:
1、
把16,17,18这三行代码的对象的状态称为临时对象,其特征是该对象与hibernate没有关系。(没有和hibernate联系)
2.持久化状态
2、
当执行19行代码的时候,person对象由临时状态转化成持久化状态,这个时候数据库没有对应的数据,但是该对象在hibernate内部
3、
当执行20行代码的时候,事务提交了,该对象还是持久化状态的对象,数据库中有对应的值了
2.脱管状态
4、
当执行完21行代码的时候,session关闭了,该对象成为脱管状态的对象(session关闭)
案例2
说明:
1、 session.get方法提取出来的是一个持久化状态的对象
2、 当事务提交的时候,hibernate内部自动更新
案例3
案例4
案例5
说明:
该例子对象的状态由持久化----->脱管----->持久化
当事务提交的时候,hibernate内部只管持久化状态的对象,对于临时状态和脱管状态是不管的。
案例6
说明:
利用session.clear方法把hibernate中所有的持久化状态转化为脱管状态。
案例7
说明:
Person对象对于第一个session而言,当session还没有关闭的时候,是持久化对象
Person对象对于第二个session而言,该对象和该session没有交互,所以一个对象是一个持久化状态的对象是针对session而言的。
对象转化图
总结
可以通过session.get,save,update,方法把一个对象变成持久化状态的对象 可以通过session.close session.evict session.clear方法把一个对象变成脱管状态的对象
Hibernate的一级缓存
缓存
数据缓存
Map<String,Object>
String是缓存中数据的唯一标示
Object是key所对应的值
对象缓存
说明:
1、 对象缓存是一个集合(List),而不是一个map 2、 每一个对象中都有一个唯一的标示符 3、 在hibernate中,该标示符为主键
缓存研究内容
缓存的生命周期:
把一个对象放入到缓存中
把一个对象从缓存中提取出来
把一个对象从缓存中清除
把一些对象从缓存中清除
把缓存中的数据同步到数据库中
把数据库中的数据同步到缓存中
一级缓存
说明:
一级缓存是session缓存
当session开启的时候,一级缓存起作用,当session关闭的时候,一级缓存销毁了
Session的缓存存放的是私有数据
操作:
把一个对象放入到一级缓存中
A:
Get方法
说明:
Session.get方法把一个对象放入到了一级缓存中
B:
Statictis方法:统计方法
说明在session的一级缓存中存放了两个对象
c:
Save方法:
说明:session.save方法把对象放入到一级缓存中了
把一个对象从一级缓存中清除:
Evict方法:
Clear方法:
Close方法:
当执行session.close方法的时候,一级缓存的生命周期结束了
把数据库的数据同步到缓存中:
Refresh方法:
把缓存中的数据同步到数据库中:
Flush方法:
说明:
当执行94行代码的时候,hibernate会检查一级缓存中所有的持久化状态的对象,
如果该持久化状态的对象没有标示符的值,则会发出insert语句,如果该持久化状态的对象有标示符的值,则会对照副本,看是否和副本一致,如果一致,则什么都不做,如果不一致,则发出update语句。
总结
一级缓存提供了一个临时存放对象的一个内存结构,当hibernate对对象进行操作的时候,仅仅改变的是对象的属性,改变的是一级缓存中的对象的属性,在session.flush之前的代码可以任意写,因为这个时候,并没有和数据库交互。当执行session.flush的时候,hibernate会检查一级缓存中的对象的情况,发出insert或者update语句。
基础部分的重点
1、 很熟练掌握内部执行流程
2、 错误分析的熟练掌握
Session的产生方式
sessionFactory.openSession方法
每一次执行openSession的时候都会新打开一个session
sessionFactory.getCurrentSession方法
原理
1、 从当前线程中(ThreadLocal)中,把session提取出来
2、 如果第一步失败,则调用openSession方法创建一个session
3、 接着第二步,把session放入到threadlocal中
4、 走第一步
好处
不管有几个类完全松耦合,如果这几个类要用到同一个session,在运行的时候,如果这几个类在同一个线程下运行,利用threadlocal就能够保证是同一个session。
步骤
1、 在hibernate.cfg.xml文件中
2、 在客户端
说明:
1、 crud操作必须在事务的环境下运行
2、 事务提交,session自动关闭。
3、 这种方式强制把事务和session绑定在一起了。
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test; import com.itheima09.hibernate.domain.Account;
import com.itheima09.hibernate.utils.HibernateUtils; public class SessionCreateMethod extends HibernateUtils{
@Test
public void testGetCurrentSession(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
Account account = (Account)session.get(Account.class, 1L);
transaction.commit();
System.out.println(session.isOpen());
}
}
SessionCreateMethod.java
关系操作
一对多的单项
持久化类和映射文件:
可以看到只能通过Classes查找到Student,但是不能通过student查找到Classes。
从映射文件可以看出,set元素描述了两个方面的内容:
1、 key从外键的角度描述了两者之间的关系,用于生成sql语句
2、 one-to-many从类与类的角度描述了两者的关系,用于客户端的编码
<?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>
<class name="com.itheima09.hibernate.domain.Classes">
<id name="cid" length="5">
<generator class="increment"></generator>
</id>
<property name="name" length="20"></property>
<property name="description" length="100"></property>
<!--
cascade 级联
save-update
当保存或者更新classes的时候,级联操作student
-->
<set name="students" cascade="save-update">
<!--
key代表外键
用来关联classes表和student表,用于在hibernate低层生成sql语句
-->
<key>
<column name="cid"></column>
</key>
<!--
建立类与类之间的关联,用于客户端的编码
-->
<one-to-many class="com.itheima09.hibernate.domain.Student"/>
</set>
</class>
</hibernate-mapping>
Classes.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>
<class name="com.itheima09.hibernate.domain.Student">
<id name="sid" length="5">
<generator class="increment"></generator>
</id>
<property name="name" length="20"></property>
<property name="description" length="100"></property>
</class>
</hibernate-mapping>
Student.hbm.xml
操作
保存班级:
保存学生
保存班级同时保存学生
这种做法不好,因为在客户端需要操作session.save这个代码很多次。
级联操作
保存班级级联保存学生
1、 在映射文件中
2、 在代码中
说明:
1、 在hibernate中,通过session.save方法保存一个持久化对象这种方式称为显示保存。
2、 在hibernate中,通过级联的方式来操作一个对象,这样的方式称为隐式操作。
3、 对student对象进行了隐式的保存操作,是因为student是一个临时状态的对象,在数据库中没有对应的记录,所以应该对student执行insert语句
更新班级级联更新学生
说明:
1、 当执行108行的时候,产生了如下的sql语句
2、 在执行110行代码的时候,产生了如下的sql语句
3、 执行114行代码的时候,产生了如下的sql语句
该update语句产生了3条,因为该班级中有3个学生,3个学生的属性同时发生改变。
4、没有发出更新classes的update语句,因为classes的属性没有发生改变。
import java.util.HashSet;
import java.util.Set; import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test; import com.itheima09.hibernate.domain.Classes;
import com.itheima09.hibernate.domain.Student;
import com.itheima09.hibernate.utils.HibernateUtils; /**
* 1、保存班级
* 2、保存学生
* 3、保存班级的同时保存学生
* 4、更新班级
* 5、更新学生
* 6、已经存在一个班级,新建一个学生,让该学生加入到该班级
* 7、已经存在两个班级,已经存在一个学生,让一个学生从一个班级转移到另外一个班级
* 8、已经存在一个班级,已经存在一个学生,解除该学生和该班级之间的关系
* 9、解除该班级和所有的学生之间的关系
* 10、删除学生
* 11、删除班级
* @author zd
*
*/
public class OneToManySingleTest extends HibernateUtils{
//1、保存班级
@Test
public void testSaveClasses(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
Classes classes = new Classes();
classes.setName("云9");
classes.setDescription("是一个神奇的班级");
session.save(classes);
transaction.commit();
}
// 2、保存学生
@Test
public void testSaveStudent(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
Student student = new Student();
student.setName("带头大哥:班长");
student.setDescription("厉害");
session.save(student);
transaction.commit();
}
//3、保存班级的同时保存学生
@Test
public void testSaveClassesAndStudent(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction(); Classes classes = new Classes();
classes.setName("java基础班");
classes.setDescription("信老毕,有肉吃"); Student student1 = new Student();
student1.setName("王二麻子");
student1.setDescription("很酷"); Student student2 = new Student();
student2.setName("上面的哥");
student2.setDescription("脸上麻子比较多"); session.save(classes);
session.save(student1);
session.save(student2);
transaction.commit();
} @Test
public void testSaveClasses_Cascade_SaveStudent(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction(); Classes classes = new Classes();
classes.setName("java基础班");
classes.setDescription("信老毕,有肉吃"); Set<Student> students = new HashSet<Student>();
Student student1 = new Student();
student1.setName("王二麻子");
student1.setDescription("很酷");
Student student2 = new Student();
student2.setName("上面的哥");
student2.setDescription("脸上麻子比较多");
students.add(student1);
students.add(student2);
//通过classe建立classes与student之间的关联
classes.setStudents(students);
session.save(classes);
transaction.commit();
} /**
* 获取cid为3的班级,再获取该班级的所有的学生,并且变化其属性
*/
@Test
public void testUpdateClasses_Cascade_UpdateStudent(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
//获取cid为3的classes
Classes classes = (Classes)session.get(Classes.class, 3L);
//获取该班级所有的学生
Set<Student> students = classes.getStudents();
for(Student student:students){
student.setDescription("aaa");
}
transaction.commit();
}
}
TestOneToMany.java
再次讨论session.flush:
1、 检查session一级缓存中所有的持久化对象的状态,决定发出insert语句或者update语句。
2、 会检查所有的持久化对象的关联对象,如果有级联操作,则对关联对象进行insert语句或者update语句。
关系操作
让一个新的学生加入到已经存在的班级
说明:
1、 当执行127行代码的时候,发出了加载classes的sql语句
2、 当执行129行代码的时候,发出了加载classes班级中的所有的学生的sql语句
3、 因为在Classes.hbm.xml文件中set元素的cascade属性设置了save-update,所以在更新classes的时候,要检查classes中的students集合,发现集合中多了一个对象,所以要对该对象(student)执行insert语句。
4、 当执行session.flush的时候,会发出维护关系的update语句,因为classes负责维护classes与student之间的关系。
重新建立关系1:
说明:
1、 执行141行的时候,发出加载student的sql语句
2、 执行143行的时候,发出加载cid为1的班级的sql语句
3、 执行144行的时候,发出加载cid为2的班级的sql语句
4、 执行146行的时候,发出维护关系的sql语句
因为解除关系了,所以cid为null
5、 执行148行的时候,
因为建立关系了,所以更新了外键。
分析:从上面的代码和sql语句可以看出,外键变了两次,但是不需要改变两次。
重新建立关系2:
说明:只需要建立关系就可以了,因为发出的是更新外键的sql语句。把外键的值改变了就可以了。
解除一个学生和一个班级之间的关系
解除该班级和所有的学生之间的关系
说明:当执行classes.setStudents(null)的时候,不需要根据班级加载学生,所以这样做效率比较高。
删除班级
说明
1、 classes负责维护关系
2、 在执行session.flush的时候,在删除班级之前,解除该班级和所有的学生之间的关系
3、 解除关系以后,再删除班级
4、 先查询班级,再查询该班级中的每一个学生,再根据每一个学生的sid删除每一个学生,这样效率比较低
删除班级级联删除学生
Cascade与inverse的区别
1、 cascade描述的是对象与对象之间的关系
cascade和外键没有关系,在student表中,sid、name、description和cascade有关系,但是cid和cascade没有关系。
2、 inverse描述的是对象与外键之间的关系
inverse只和cid有关系,如果维护,则发出update语句(更新外键的sql语句),如果不维护,则不管。
总结
1、 只能通过classes操作student 2、 只要classes维护关系,就会发出维护关系的update语句,所以让classes维护关系效率比较低 3、 让student维护关系效率比较高 4、 Session.flush的时候,hibernate内部做的事情 1、 检查一级缓存中所有的持久化对象,决定发出insert语句还是update语句 2、 检查持久化对象的关联对象,看持久化对象的映射文件中的cascade,决定关联对象是否发出insert语句或者update语句或者delete语句 3、 检查持久化对象的映射文件的针对关联对象的inverse属性,来决定是否维护关系。如果维护关系,则发出update语句(维护关系的语句)
一对多的双向
持久化类和映射文件
操作
保存学生级联保存班级
说明:
1、36行代码是通过student建立student与classes之间的关联,所以看student.hbm.xml文件
2、在Student.hbm.xml文件中,设置了针对classes的级联
3、在保存学生的时候级联保存了班级
4、保存学生相当于维护了关系
在保存学生的时候,cid有值了,不需要发出维护关系的update语句。
新建一个学生,并且和一个已经的班级关联:
学生转班:
说明:从上述的sql语句可以看出不仅更新了外键,而且把其他属性也更新了,所以更新关系指的就是更新student对象本身的操作。
解除一个班级和一个学生之间的关系:
解除该班级和所有的学生的关系:
这样做是通过学生解除学生和班级之间的关系,但是效率不高。
总结
一般情况下,一对多,多的一方维护关系效率要比较高。
import java.io.Serializable;
import java.util.Set; public class Classes implements Serializable{
private Long cid;
private String name;
private String description;
private Set<Student> students;
public Long getCid() {
return cid;
}
public void setCid(Long cid) {
this.cid = cid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Set<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) {
this.students = students;
}
}
Classes.java
import java.io.Serializable; public class Student implements Serializable{
private Long sid;
private String name;
private String description;
private Classes classes; public Classes getClasses() {
return classes;
}
public void setClasses(Classes classes) {
this.classes = classes;
}
public Long getSid() {
return sid;
}
public void setSid(Long sid) {
this.sid = sid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
Student.java
<?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>
<class name="com.itheima09.hibernate.domain.Student">
<id name="sid" length="5">
<generator class="increment"></generator>
</id>
<property name="name" length="20"></property>
<property name="description" length="100"></property>
<!--
column 为外键
-->
<many-to-one name="classes" column="cid"
class="com.itheima09.hibernate.domain.Classes" cascade="save-update">
</many-to-one>
</class>
</hibernate-mapping>
Student.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>
<class name="com.itheima09.hibernate.domain.Classes">
<id name="cid" length="5">
<generator class="increment"></generator>
</id>
<property name="name" length="20"></property>
<property name="description" length="100"></property>
<!--
cascade 级联
save-update
当保存或者更新classes的时候,级联操作student
inverse 维护关系
true 不维护关系
false 维护关系
default false
-->
<set name="students" cascade="all">
<!--
key代表外键
用来关联classes表和student表,用于在hibernate低层生成sql语句
-->
<key>
<column name="cid"></column>
</key>
<!--
建立类与类之间的关联,用于客户端的编码
-->
<one-to-many class="com.itheima09.hibernate.domain.Student"/>
</set>
</class>
</hibernate-mapping>
Classes.hbm.xml
import java.util.Set; import javax.annotation.Generated; import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test; import com.itheima09.hibernate.domain.Classes;
import com.itheima09.hibernate.domain.Student;
import com.itheima09.hibernate.utils.HibernateUtils; /**
* 1、保存班级
* 2、保存学生
* 3、保存班级的同时保存学生
* 4、更新班级
* 5、更新学生
* 6、已经存在一个班级,新建一个学生,让该学生加入到该班级
* 7、已经存在两个班级,已经存在一个学生,让一个学生从一个班级转移到另外一个班级
* 8、已经存在一个班级,已经存在一个学生,解除该学生和该班级之间的关系
* 9、解除该班级和所有的学生之间的关系
* 10、删除学生
* 11、删除班级
* @author zd
*
*/
public class OneToManyTest extends HibernateUtils{
@Test
public void testSaveStudent_Cascade_SaveClasses(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
Student student = new Student();
student.setName("c罗");
Classes classes = new Classes();
classes.setName("皇马");
//通过student建立student与classes之间的关联
student.setClasses(classes);
session.save(student);
transaction.commit();
} /**
* 已经存在一个班级,新建一个学生,让该学生加入到该班级
*/
@Test
public void testSaveStudent_BuildR(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
//把 cid为4的班级提取出来
Classes classes = (Classes)session.get(Classes.class, 4L);
Student student = new Student();
student.setName("梅西");
//通过student建立关联
student.setClasses(classes);
session.save(student);
transaction.commit();
}
/**
* 一个学生从一个班级转移到另外一个班级
* sid为8的学生从cid为2的班级转移到cid为1的班级
*/
@Test
public void testTransform(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
Student student = (Student)session.get(Student.class, 8L);
Classes classes =(Classes)session.get(Classes.class, 1L);
//student有一个新的班级
student.setClasses(classes);
transaction.commit();
} /**
* 解除一个学生和一个班级之间的关系
*/
@Test
public void testReleaseR(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
Student student = (Student)session.get(Student.class, 9L);
student.setClasses(null);
transaction.commit();
} /**
* 解除该班级和所有的学生之间的关系
*/
@Test
public void testReleaseAll(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
Classes classes = (Classes)session.get(Classes.class, 1L);
Set<Student> students = classes.getStudents();
for(Student student:students){
student.setClasses(null);
}
transaction.commit();
}
}
OneToManyTest.java
多对多的双向
持久化和映射文件:
关系的维护:
1、 建立关系,相当于在第三张表中插入一行数据
2、 解除关系,相当于在第三张表中删除一行数据
3、 重新建立关系,相当于先删除一行数据,再增加一行数据
4、 多对多,谁维护关系效率都一样
操作:
让一个新的学生和一个已经存在的课程发生关联:
说明:
1、65行代码是通过课程建立课程与学生之间的关联,course.getStudents()的时候会发出根据课程查找该学生的sql语句,这样做效率比较低
解除一个学生和一门课程之间的关系
解除该课程和所有的学生之间的关联:
一个学生从一门课程转移到另外一门课程:
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<!--
一个session-factory代表一个数据库
-->
<session-factory>
<!--
链接数据库的用户名
-->
<property name="connection.username">root</property>
<!--
链接数据库的密码
-->
<property name="connection.password">root</property>
<!--
链接数据库的驱动
-->
<property name="connection.driver_class">
com.mysql.jdbc.Driver
</property>
<!--
链接数据库的url
-->
<property name="connection.url">
jdbc:mysql://localhost:3306/itheima09_hibernate
</property>
<!--
方言
告诉hibernate用什么样的数据库
-->
<property name="dialect">
org.hibernate.dialect.MySQLDialect
</property>
<!--
validate 加载hibernate时,验证数据库的结构
update 加载hibernate时,检查数据库,如果表不存在,则创建,如果存在,则更新
create 每次加载hiberante,都会创建表
create-drop 每次加载hiberante,创建,卸载hiberante时,销毁
-->
<property name="hbm2ddl.auto">update</property>
<!--
显示sql语句
-->
<property name="show_sql">true</property>
<!--
格式化sql语句
-->
<property name="format_sql">true</property>
<!--
session要从当前线程中产生
-->
<property name="current_session_context_class">thread</property>
<!--
加载映射文件
-->
<mapping resource="com/itheima09/hibernate/domain/Course.hbm.xml" />
<mapping resource="com/itheima09/hibernate/domain/Student.hbm.xml" />
</session-factory>
</hibernate-configuration>
hibernate.cfg.xml
import java.io.Serializable;
import java.util.Set; public class Course implements Serializable{
private Long cid;
private String name;
private String description;
private Set<Student> students;
public Long getCid() {
return cid;
}
public void setCid(Long cid) {
this.cid = cid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Set<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) {
this.students = students;
}
}
Course.java
<?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>
<class name="com.itheima09.hibernate.domain.Course">
<id name="cid" length="5">
<generator class="increment"></generator>
</id>
<property name="name" length="20"></property>
<property name="description" length="50"></property>
<set name="students" table="student_course" cascade="save-update">
<key>
<column name="cid"></column>
</key>
<many-to-many class="com.itheima09.hibernate.domain.Student"
column="sid"></many-to-many>
</set>
</class>
</hibernate-mapping>
Course.hbm.xml
package com.itheima09.hibernate.domain; import java.io.Serializable;
import java.util.Set; public class Student implements Serializable{
private Long sid;
private String name;
private String description;
private Set<Course> courses;
public Long getSid() {
return sid;
}
public void setSid(Long sid) {
this.sid = sid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Set<Course> getCourses() {
return courses;
}
public void setCourses(Set<Course> courses) {
this.courses = courses;
}
}
Student.java
<?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>
<class name="com.itheima09.hibernate.domain.Student">
<id name="sid" length="5">
<generator class="increment"></generator>
</id>
<property name="name" length="20"></property>
<property name="description" length="50"></property>
<!--
table为关联表
为了生成关联的sql语句
-->
<set name="courses" table="student_course" cascade="save-update">
<!--
外键
-->
<key>
<column name="sid"></column>
</key>
<many-to-many class="com.itheima09.hibernate.domain.Course"
column="cid"></many-to-many>
</set>
</class>
</hibernate-mapping>
Student.hbm.xml
import java.util.HashSet;
import java.util.Set; import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test; import com.itheima09.hibernate.domain.Course;
import com.itheima09.hibernate.domain.Student;
import com.itheima09.hibernate.utils.HibernateUtils; /**
* 1、保存课程,同时保存学生(级联)
* 2、更新课程,同时更新学生(级联)
* 3、已经存在一门课程,新建一个学生,让该学生加入到该课程
* 4、已经存在一个学生,新建一门课程,让该学生加入到该课程
* 5、解除一门课程和一个学生之间的关系
* 6、解除一门课程和这门课程所有的学生之间的关系
* 7、删除课程
* 8、删除学生
* 9、一个学生从一门课程转移到另外一个门课程
* @author zd
*
*/
public class ManyToManyTest extends HibernateUtils{
@Test
public void testCreateTable(){ } /**
* 保存课程,同时保存学生
*/
@Test
public void testSaveStudent_Cascade_SaveCourse(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
Student student = new Student();
student.setName("aaa");
Course course = new Course();
course.setName("java基础");
//通过保存学生级联保存课程
Set<Course> courses = new HashSet<Course>();
courses.add(course);
//建立了学生和课程之间的关系
student.setCourses(courses);
session.save(student);
transaction.commit();
} /**
* 已经存在一门课程,新建一个学生,让该学生加入到该课程
*/
@Test
public void testSaveStudent_BuildR(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
//得到cid为1的课程
Course course = (Course)session.get(Course.class, 1L);
//新建一个学生
Student student = new Student();
student.setName("aaa");
//建立该课程和该学生之间的关联
//course.getStudents().add(student); //通过课程关联学生 根据课程查找学生要发出sql语句
Set<Course> courses = new HashSet<Course>();
courses.add(course);
student.setCourses(courses); //通过学生建立学生和课程之间的关联
session.save(student);
transaction.commit();
} /**
* 解除一门课程和一个学生之间的关系
*/
@Test
public void testReleaseR(){
/**
* 解除cid为1的课程和sid为1的学生之间的关系
*/
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
Course course = (Course)session.get(Course.class, 1L);
Student student = (Student)session.get(Student.class, 1L);
course.getStudents().remove(student);//通过course解除关系
//student.getCourses().remove(course);//通过student解除关系
transaction.commit();
} /**
* 解除一门课程和这门课程所有的学生之间的关系
*/
@Test
public void testReleaseAllR(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
/**
* 解除cid为1的课程和该课程所有的学生之间的关系
*/
Course course = (Course)session.get(Course.class, 1L);
course.setStudents(null);
transaction.commit();
} /**
* 一个学生从一门课程转移到另外一个门课程
* 把sid为1的学生从cid为1的课程转移到cid为2的课程
*/
@Test
public void testTransform(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
//以学生维护关系
Student student = (Student)session.get(Student.class, 1L);
Course course1 =(Course)session.get(Course.class, 1L);
Course course2 = (Course)session.get(Course.class, 2L);
student.getCourses().remove(course1);//移除
student.getCourses().add(course2);//增加
transaction.commit();
}
}
ManyToManyTest.java
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration; public class HibernateUtils {
public static SessionFactory sessionFactory;
static{
Configuration configuration = new Configuration();
configuration.configure();
sessionFactory = configuration.buildSessionFactory();
}
}
HibernateUtils.java
一对一的双向
所以上面的代码是不对的,因为上面的代码会导致student2和student1的外键都为6L。
总结
1、 关系的角度 一对多反映的是类与集合的关系 多对一反映的是类与类之间的关系 多对多反映的是类与集合之间的关系 2、 一对多,多的一方维护关系,效率比较高 3、 多对多,谁维护效率都一样 4、 通过谁建立关系,看谁的映射文件 5、 Cascade与inverse之间的区别
性能分析
抓取策略
研究对象
研究怎么样提取集合的,该策略应该作用与set元素上
研究从一的一方加载多的一方
案例
查询cid为1的班级的所有的学生
说明:通过一条sql语句:左外链接,把classes与student表的数据全部提取出来。
如果是如下的策略:
先查询classes,再次查询student
先查询classes,再次查询student。
查询所有的班级的所有的学生
该需求翻译过来含有子查询
如果含有子查询,必须用subselect
改进:
查询班级为1,2,3,4的所有的学生
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration; public class HibernateUtils {
public static SessionFactory sessionFactory;
static{
Configuration configuration = new Configuration();
configuration.configure();
sessionFactory = configuration.buildSessionFactory();
}
}
HibernateUtils.java
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<!--
一个session-factory代表一个数据库
-->
<session-factory>
<!--
链接数据库的用户名
-->
<property name="connection.username">root</property>
<!--
链接数据库的密码
-->
<property name="connection.password">root</property>
<!--
链接数据库的驱动
-->
<property name="connection.driver_class">
com.mysql.jdbc.Driver
</property>
<!--
链接数据库的url
-->
<property name="connection.url">
jdbc:mysql://localhost:3306/itheima09_hibernate
</property>
<!--
方言
告诉hibernate用什么样的数据库
-->
<property name="dialect">
org.hibernate.dialect.MySQLDialect
</property>
<!--
validate 加载hibernate时,验证数据库的结构
update 加载hibernate时,检查数据库,如果表不存在,则创建,如果存在,则更新
create 每次加载hiberante,都会创建表
create-drop 每次加载hiberante,创建,卸载hiberante时,销毁
-->
<property name="hbm2ddl.auto">update</property>
<!--
显示sql语句
-->
<property name="show_sql">true</property>
<!--
格式化sql语句
-->
<property name="format_sql">true</property>
<!--
session要从当前线程中产生
-->
<property name="current_session_context_class">thread</property>
<!--
加载映射文件
-->
<mapping resource="com/itheima09/hibernate/domain/Classes.hbm.xml" />
<mapping resource="com/itheima09/hibernate/domain/Student.hbm.xml" />
</session-factory>
</hibernate-configuration>
hibernate.cfg.xml
import java.io.Serializable;
import java.util.Set; public class Classes implements Serializable{
private Long cid;
private String name;
private String description;
private Set<Student> students;
public Long getCid() {
return cid;
}
public void setCid(Long cid) {
this.cid = cid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Set<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) {
this.students = students;
}
}
Classes.java
<?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>
<class name="com.itheima09.hibernate.domain.Classes">
<id name="cid" length="5">
<generator class="increment"></generator>
</id>
<property name="name" length="20"></property>
<property name="description" length="100"></property>
<!--
fetch 抓取策略
join 通过做外链接
select 默认值
subselect
-->
<set name="students" cascade="all" fetch="subselect">
<!--
key代表外键
用来关联classes表和student表,用于在hibernate低层生成sql语句
-->
<key>
<column name="cid"></column>
</key>
<!--
建立类与类之间的关联,用于客户端的编码
-->
<one-to-many class="com.itheima09.hibernate.domain.Student"/>
</set>
</class>
</hibernate-mapping>
Classes.hbm.xml
import java.io.Serializable; public class Student implements Serializable{
private Long sid;
private String name;
private String description;
private Classes classes; public Classes getClasses() {
return classes;
}
public void setClasses(Classes classes) {
this.classes = classes;
}
public Long getSid() {
return sid;
}
public void setSid(Long sid) {
this.sid = sid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
Student.java
<?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>
<class name="com.itheima09.hibernate.domain.Student">
<id name="sid" length="5">
<generator class="increment"></generator>
</id>
<property name="name" length="20"></property>
<property name="description" length="100"></property>
<!--
column 为外键
-->
<many-to-one name="classes" column="cid"
class="com.itheima09.hibernate.domain.Classes" cascade="save-update">
</many-to-one>
</class>
</hibernate-mapping>
Student.hbm.xml
import java.util.List;
import java.util.Set; import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test; import com.itheima09.hibernate.domain.Classes;
import com.itheima09.hibernate.domain.Student;
import com.itheima09.hibernate.utils.HibernateUtils; public class FetchTest extends HibernateUtils{
@Test
public void testCreateTable(){ } /**
* 获取到所有的班级的所有的学生
* 如果采用默认的策略,会导致n+1条sql语句,n为classes表中的行数
*/
@Test
public void testGetAllClassesAndStudent(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
List<Classes> classesList = session.createQuery("from Classes").list();
for(Classes classes:classesList){
Set<Student> students = classes.getStudents();
for(Student student:students){
System.out.println(student.getName());
}
}
transaction.commit();
} /**
* 获取cid为1的班级,再获取cid为1的班级的所有的学生
*/
@Test
public void testGetClassesAndStudent(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
Classes classes = (Classes)session.get(Classes.class, 1L);
Set<Student> students = classes.getStudents();
for(Student student:students){
System.out.println(student.getName());
}
transaction.commit();
} /**
* 查询cid为1,2,3,4的班级的学生
*/
@Test
public void testQueryStudentFromClassesIn(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
List<Classes> classesList = session.createQuery("from Classes where cid in(1,2,3,4)").list();
for(Classes classes:classesList){
Set<Student> students = classes.getStudents();
for(Student student:students){
System.out.println(student.getName());
}
}
transaction.commit();
}
}
FetchTest.java
总结
1、 研究对象是集合
2、 经过分析,如果sql语句中含有了子查询,则用subselect效率比较高
3、 如果页面上需要一次性把两张表的数据全部提取出来,用join效率比较高
因为采用”join”为左外链接
4、 如果用select,先查询班级,后查询学生,如果查询班级的个数超过1个,会导致n+1条sql语句
5、 抓取策略是hibernate提供的一种优化方式而已
延迟加载(懒加载)
概念
需要用到该数据的时候才要加载(详情请见笔记二)
错误分析:
错误一
分析:person表不存在
一般的原因是在hibernate.cfg.xml文件中没有加入该配置
错误二
错误原因:hibernate不认为该类是一个持久化类,因为在所有的映射文件中的class元素的name属性中没有发现该类
错误三
错误原因:找到了映射文件,但是映射文件中的class元素的name属性描述的类是一个不存在的类
错误四
错误原因: 在拼接sql语句的时候,映射文件中的property元素的name属性的值和持久化类的属性不一样,所以拼接不出来getter方法
错误五
错误原因:
谨记:在实际开发中如果重写类的构造方法最好将省缺构造方法也写出
错误六
在执行save方法之前,必须手动赋值主键的值,因为在映射文件中,使用了assigned主键的生成机制。
错误七
错误原因: 该主键的生成策略说明了支持主键的自动增加,但是在该表中
不支持这种
错误八
错误原因:
如果用当先线程获取session,crud操作必须在事务的环境下运行
错误九
分析:
1、 在客户端
试图通过显示保存classes来隐式保存student,但是在Classes.hbm.xml文件中的set元素中没有设置cascade属性
错误十
在Classes.hbm.xml文件中
在客户端
Student对象是从classes对象中获取到的,也就是说student对象是classes对象的关联对象。
所以在没有解除classes与student关系之前,不能删除student。
所以应该先解除关系:
Hibernate笔记一的更多相关文章
- 框架Hibernate笔记系列 基础Session
标题:框架Hibernate笔记 资料地址: 1. www.icoolxue.com 孔浩 1.背景简介 Hibenate是JBoss公司的产品.它是数据持久化的框架.Usually,我们使用JDBC ...
- hibernate笔记--cascade级联以及inverse属性
cascade : 不管是单向多对一还是一对多,或者是双向的一对多关系,在一的一端映射文件中有一个set标签,在多的一端有many-to-one标签,拿前几篇笔记里讲的Grade和Student举例, ...
- Hibernate 笔记 HQL查询 条件查询,聚集函数,子查询,导航查询
在hibernate中进行多表查询,每个表中各取几个字段,也就是说查询出来的结果集并没有一个实体类与之对应,如何解决这个问题? 解决方案一,按照Object[]数据取出数据,然后自己组bean 解决方 ...
- hibernate笔记--缓存机制之 二级缓存(sessionFactory)和查询缓存
二级缓存(sessionFactory): Hibernate的二级缓存由SessionFactory对象管理,是应用级别的缓存.它可以缓存整个应用的持久化对象,所以又称为“SessionFactor ...
- hibernate笔记--缓存机制之 一级缓存(session缓存)
一级缓存: 又称为session缓存,它和session生命周期相同,周期非常短.是事务级别的缓存: 还是以Book和Category这两个表为例,我们用代码观察一个缓存的存在: 假设现在我要去查询i ...
- hibernate笔记--使用注解(annotation)方式配置单(双)向多对一的映射关系
前面几篇都是介绍的用配置文件来实现实体类到数据库表的映射,这种方式是比较麻烦的,每一个pojo类都需要写一个相应的*.hbm.xml,无疑增加了很多代码量,不过也有优点就是利于维护,为了方便开发,Hi ...
- hibernate笔记--继承映射关系的三种实现方式
单表继承映射(一张表): 假设我们现在有三个类,关系如下: Person类有两个子类Student和Teacher,并且子类都具有自己独有的属性.这种实体关系在hibernate中可以使用单表的继承映 ...
- hibernate笔记--单(双)向的多对多映射关系
在讲单向的多对多的映射关系的案例时,我们假设我们有两张表,一张角色表Role,一张权限表Function,我们知道一个角色或者说一个用户,可能有多个操作权限,而一种操作权限同时被多个用户所拥有,假如我 ...
- hibernate笔记--基于主键的单(双)向的一对一映射关系
上一节介绍的基于外键的一对一映射关系中,在Person表中有一个外键列idCard_id,对应的idCard表的主键id,至于基于主键的一对一映射关系,就是指Person表中抛弃了idcard_id这 ...
随机推荐
- 鬼斧神工:求n维球的体积
原文地址:http://spaces.ac.cn/archives/3154/ 原文作者:苏剑林 标准思路 简单来说,\(n\)维球体积就是如下\(n\)重积分 \[V_n(r)=\int_{x_1^ ...
- java 实体类 时间格式字段注解
@DatetimeFormat是将String转换成Date,一般前台给后台传值时用 @JsonFormat(pattern="yyyy-MM-dd") 将Date转换成Strin ...
- 每天进步一点点------Sobel算子(3)基于彩色图像边缘差分的运动目标检测算法
摘 要: 针对目前常用的运动目标提取易受到噪声影响.易出现阴影和误检漏检等情况,提出了一种基于Sobel算子的彩色边缘图像检测和帧差分相结合的检测方法.首先用Sobel算子提取视频流中连续4帧图像的 ...
- 每天进步一点点------时序分析基础与时钟约束实例(四)IO口时序(Input Delay /output Delay)
1.1 概述 在高速系统中FPGA时序约束不止包括内部时钟约束,还应包括完整的IO时序约束和时序例外约束才能实现PCB板级的时序收敛.因此,FPGA时序约束中IO口时序约束也是一个重点.只有约束正确 ...
- Django报错 The serializer field might be named incorrectly and not match any Got AttributeError when attempting to get a value for field `author_for` on serializer `KnownledgeBaseListSerializer`
1.问题描述,在设置,model部分字段的serialier时,出现如下报错 字段如下: # 知识库List class KnownledgeBaseListSerializer(serializer ...
- 官方不再支持Python2,如何将你的项目完美迁移到Python3?
Python 2.x 很快就要失去官方支持了,不过不用慌,从 Python 2 迁移到 Python 3 却并没有想象中那么难.我在上周用了一个晚上的时间将一个 3D 渲染器的前端代码及其对应的 Py ...
- springboot 注解@EnableConfigurationProperties @ConfigurationProperties作用
@EnableConfigurationProperties 在springboot启动类添加,当springboot程序启动时会立即加载@EnableConfigurationProperties注 ...
- 一个汇编小demo
一个小demo: #include<stdio.h> void main(){ ; char *str="i=%d\n"; printf("begin\n&q ...
- Cookie API介绍
一.Java提供的操作Cookie的API Java中的javax.servlet.http.Cookie类用于创建一个Cookie Cookie类的主要方法 No. 方法 类型 描述 Cookie( ...
- 分布式事务 --- BASE 理论
部分图片总结出自参考资料 问题 : Base 理论为什么会被提出,动机是什么 Base 和 ACID 的区别与联系 概述 上一篇我们知道CAP 理论,也知道由于现实中网络等原因,分区容错性这一元素大多 ...