Hibernate 简介

Hibernate 是由 Gavin King 于 2001 年创建的开放源代码的对象关系框架。它强大且高效的构建具有关系对象持久性和查询服务的 Java 应用程序。

Hibernate 将 Java 类映射到数据库表中,从 Java 数据类型中映射到 SQL 数据类型中,并把开发人员从 95% 的公共数据持续性编程工作中解放出来。

Hibernate 是传统 Java 对象和数据库服务器之间的桥梁,用来处理基于 O/R 映射机制和模式的那些对象。

Hibernate 优势

  • Hibernate 使用 XML 文件来处理映射 Java 类别到数据库表格中,并且不用编写任何代码。
  • 为在数据库中直接储存和检索 Java 对象提供简单的 APIs。
  • 如果在数据库中或任何其它表格中出现变化,那么仅需要改变 XML 文件属性。
  • 抽象不熟悉的 SQL 类型,并为我们提供工作中所熟悉的 Java 对象。
  • Hibernate 不需要应用程序服务器来操作。
  • 操控你数据库中对象复杂的关联。
  • 最小化与访问数据库的智能提取策略。
  • 提供简单的数据询问。

基础

一、第一个hibernate程序

1、本例演示如何使用hibernate往数据库插入一条数据。如图,这条iphone7的产品数据,就是由hibernate插入的

2、准备数据库test
create database test;
3、创建表
/*准备表product_, 有3个字段,分别是
主键id(自增长)
字符串格式的name
浮点数格式的price*/use test;CREATE TABLE product_ (id int(11) NOT NULL AUTO_INCREMENT,name varchar(30) ,price float ,PRIMARY KEY (id)
) DEFAULT CHARSET=UTF8;
4、创建一个maven project
5、导入hibernate所依赖的jar包
<dependency><groupId>org.hibernate</groupId><artifactId>hibernate-core</artifactId><version>5.1.0.Final</version>
</dependency><!-- for JPA, use hibernate-entitymanager instead of hibernate-core -->
<dependency><groupId>org.hibernate</groupId><artifactId>hibernate-entitymanager</artifactId><version>5.1.0.Final</version>
</dependency><!-- optional --><dependency><groupId>org.hibernate</groupId><artifactId>hibernate-osgi</artifactId><version>5.1.0.Final</version>
</dependency>
<dependency><groupId>org.hibernate</groupId><artifactId>hibernate-envers</artifactId><version>5.1.0.Final</version>
</dependency>
<dependency><groupId>org.hibernate</groupId><artifactId>hibernate-c3p0</artifactId><version>5.1.0.Final</version>
</dependency>
<dependency><groupId>org.hibernate</groupId><artifactId>hibernate-proxool</artifactId><version>5.1.0.Final</version>
</dependency>
<dependency><groupId>org.hibernate</groupId><artifactId>hibernate-infinispan</artifactId><version>5.1.0.Final</version>
</dependency>
<dependency><groupId>org.hibernate</groupId><artifactId>hibernate-ehcache</artifactId><version>5.1.0.Final</version>
</dependency>

6、创建实体类

实体类 Product 用于映射数据库中的表product_

package com.how2java.pojo;public class Product {int id;String name;float price;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 float getPrice() {return price;}public void setPrice(float price) {this.price = price;}}
7、配置Product.hbm.xml

新建一个配置文件Product.hbm.xml, 用于映射Product类对应数据库中的product_表

注: 文件名 Product.hbm.xml P一定要大写,要和类保持一致

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC"-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"><hibernate-mapping package="com.how2java.pojo">
<!--表示类Product对应表product_--><class name="Product" table="product_"><!--表示属性id,映射表里的字段id
<generator class="native"> 意味着id的自增长方式采用数据库的本地方式如果是连接oracle数据库,可以指定sequnce作为id自增长方式--><id name="id" column="id"><generator class="native"></generator></id><!--只写了属性name,没有通过column="name" 显式的指定字段,那么字段的名字也是name.--><property name="name" /><property name="price" /></class></hibernate-mapping>
8、配置 hibernate.cfg.xml

创建 hibernate.cfg.xml
配置访问数据库要用到的驱动,url,账号密码等等

<?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><!-- Database connection settings --><property name="connection.driver_class">com.mysql.jdbc.Driver</property><property name="connection.url">jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8</property><property name="connection.username">root</property><property name="connection.password">admin</property><!-- SQL dialect --><!--这表示使用MYSQL方言--><property name="dialect">org.hibernate.dialect.MySQLDialect</property><!--Hibernate事务管理方式,即每个线程一个事务--><property name="current_session_context_class">thread</property><!--是否在控制台显示执行的sql语句--><property name="show_sql">true</property><!--是否会自动更新数据库的表结构,有这句话,其实是不需要创建表的,因为Hibernate会自动去创建表结构--><property name="hbm2ddl.auto">update</property><!--表示Hibernate会去识别Product这个实体类--><mapping resource="com/how2java/pojo/Product.hbm.xml" /></session-factory></hibernate-configuration>
9、测试类 TestHibernate
package com.how2java.test;import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;import com.how2java.pojo.Product;/*创建一个Product对象,并通过hibernate把这个对象,插入到数据库中hibernate的基本步骤是:
1. 获取SessionFactory
2. 通过SessionFactory 获取一个Session
3. 在Session基础上开启一个事务
4. 通过调用Session的save方法把对象保存到数据库
5. 提交事务
6. 关闭Session
7. 关闭SessionFactory*/public class TestHibernate {public static void main(String[] args) {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s = sf.openSession();s.beginTransaction();Product p = new Product();p.setName("iphone7");p.setPrice(7000);s.save(p);s.getTransaction().commit();s.close();sf.close();}}
10、基本原理
应用程序通过Hibernate把 一个 Product对象插入到数据库的product_表中
hibernate.cfg.xml 配置文件提供链接数据库的基本信息
账号 密码 驱动 数据库ip 端口
Product.hbm.xml 提供对象与表的映射关系
对应哪个表? 什么属性,对应什么字段

二、插入

1、通过Hibernate可以很方便的批量插入数据到数据库中,这是插入10条数据的效果

2、使用Session的save方法插入数据。 这里插入多条数据,是为了后面学习删除,分页等功能做铺垫
package com.how2java.test;import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;import com.how2java.pojo.Product;public class TestHibernate {public static void main(String[] args) {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s = sf.openSession();s.beginTransaction();//批量插入for (int i = 0; i < 10; i++) {//这里如果把创建对象写在外面,那么最后只提交了一个对象,即只插入了一条数据Product p = new Product();p.setName("iphone"+i);p.setPrice(i);//每次循环调用saves.save(p);         }s.getTransaction().commit();s.close();sf.close();}}

三、对象状态

实体类对象在Hibernate中有3种状态

分别是瞬时,持久和脱管

瞬时 指的是没有和hibernate发生任何关系,在数据库中也没有对应的记录,一旦JVM结束,这个对象也就消失了
持久 指得是一个对象和hibernate发生联系,有对应的session,并且在数据库中有对应的一条记录
脱管 指的是一个对象虽然在数据库中有对应的一条记录,但是它所对应的session已经关闭了new 了一个Product();,在数据库中还没有对应的记录,这个时候Product对象的状态是瞬时的。 通过Session的save把该对象保存在了数据库中,该对象也和Session之间产生了联系,此时状态是持久的。最后把Session关闭了,这个对象在数据库中虽然有对应的数据,但是已经和Session失去了联系,相当于脱离了管理,状态就是脱管的

演示

package com.how2java.test;import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;import com.how2java.pojo.Product;public class TestHibernate {/*** @param args*/public static void main(String[] args) {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s = sf.openSession();s.beginTransaction();Product p = new Product();p.setName("p1");System.out.println("此时p是瞬时状态");s.save(p);System.out.println("此时p是持久状态");s.getTransaction().commit();s.close();System.out.println("此时p是脱管状态");sf.close();}}

四、获取

通过id获取对象
package com.how2java.test;import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;import com.how2java.pojo.Product;public class TestHibernate {public static void main(String[] args) {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s = sf.openSession();s.beginTransaction();//获取到id=6的产品的名称Product p =(Product) s.get(Product.class, 6);System.out.println("id=6的产品名称是: "+p.getName());s.getTransaction().commit();s.close();sf.close();}}

结果:

五、删除

根据id把对象从表里删除掉

注意:hibernate在删除一条数据之前,先要通过id把这条记录取出来

package com.how2java.test;import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;import com.how2java.pojo.Product;public class TestHibernate {public static void main(String[] args) {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s = sf.openSession();s.beginTransaction();//先取再删除Product p =(Product) s.get(Product.class, 5);s.delete(p);s.getTransaction().commit();s.close();sf.close();}}

六、修改

通过Hibernate修改数据库中的数据。 把id=6的产品名称修改为 iphone-modifed

  1. 根据id获取该对象
  2. 修改该对象的属性
  3. 通过Session的update方法把变化更新到数据库中
package com.how2java.test;import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;import com.how2java.pojo.Product;public class TestHibernate {public static void main(String[] args) {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s = sf.openSession();s.beginTransaction();//获取对象Product p =(Product) s.get(Product.class, 6);System.out.println(p.getName());//修改对象p.setName("iphone-modified");//保存s.update(p);s.getTransaction().commit();s.close();sf.close();}}

七、查询——hql

HQL(Hibernate Query Language)
是hibernate专门用于查询数据的语句,
有别于SQL,HQL 更接近于面向对象的思维方式。 比如使用的是类的名字Product,而非表格的名字product_
这是通过Hibernate对所有数据查询的结果页面

package com.how2java.test;import java.util.List;import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;import com.how2java.pojo.Product;/*1. 首先根据hql创建一个Query对象
2. 设置参数(和基1的PreparedStatement不一样,Query是基0的)
3. 通过Query对象的list()方法即返回查询的结果了。注: 使用hql的时候,用的是类名Product,而不是表名product_
注: 使用hql的时候,不需要在前面加 select **/public class TestHibernate {public static void main(String[] args) {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s = sf.openSession();s.beginTransaction();//开始String name = "iphone";Query q =s.createQuery("from Product p where p.name like ?");q.setString(0, "%"+name+"%");//接收结果List<Product> ps= q.list();for (Product p : ps) {System.out.println(p.getName());}s.getTransaction().commit();s.close();sf.close();}}

八、查询——Criteria

使用Criteria进行数据查询。
与HQL和SQL的区别是Criteria 完全是 面向对象的方式在进行数据查询,
将不再看到有sql语句的痕迹
和使用HQL 进行查询得到的结果一样

package com.how2java.test;import java.util.List;import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.criterion.Restrictions;import com.how2java.pojo.Product;/*使用Criteria 查询数据
1. 通过session的createCriteria创建一个Criteria 对象
2. Criteria.add 增加约束。 在本例中增加一个对name的模糊查询(like)
3. 调用list()方法返回查询结果的集合除此之外,Criteria 还可以很方便的进行进行分页查询和获取总数*/public class TestHibernate {public static void main(String[] args) {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s = sf.openSession();s.beginTransaction();String name = "iphone";//开始Criteria c= s.createCriteria(Product.class);c.add(Restrictions.like("name", "%"+name+"%"));//获取结果List<Product> ps = c.list();for (Product p : ps) {System.out.println(p.getName());}s.getTransaction().commit();s.close();sf.close();}
}

九、查询——标准sql

通过标准SQL语句进行查询
Hibernate依然保留了对标准SQL语句的支持,在一些场合,
比如多表联合查询,并且有分组统计函数的情况下,标准SQL语句依然是效率较高的一种选择
与使用 HQL和Criteria 进行查询的效果一样

package com.how2java.test;import java.util.List;import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;/*使用Session的createSQLQuery方法执行标准SQL语句因为标准SQL语句有可能返回各种各样的结果,比如多表查询,分组统计结果等等。 不能保证其查询结果能够装进一个Product对象中,所以返回的集合里的每一个元素是一个对象数组。 然后再通过下标把这个对象数组中的数据取出来。*/public class TestHibernate {public static void main(String[] args) {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s = sf.openSession();s.beginTransaction();String name = "iphone";//开始String sql = "select * from product_ p where p.name like '%"+name+"%'";Query q= s.createSQLQuery(sql);//获取结果List<Object[]> list= q.list();for (Object[] os : list) {for (Object filed: os) {System.out.print(filed+"\t");}System.out.println();}s.getTransaction().commit();s.close();sf.close();}
}

关系

一、多对一

一个Product对应一个Category
一个Category对应多个Product
所以Product和Category是多对一的关系
通过多对一关系,设置了id=8的产品对应 id=1的分类

1、准备Category.java
package com.how2java.pojo;public class Category {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;}int id;String name;
}
2、准备Category.hbm.xml
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC"-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.how2java.pojo"><class name="Category" table="category_"><id name="id" column="id"><generator class="native"></generator></id><property name="name" /></class></hibernate-mapping>
3、为Product.java增加Category属性
package com.how2java.pojo;
public class Product {int id;String name;float price;Category category;public Category getCategory() {return category;}public void setCategory(Category category) {this.category = category;}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 float getPrice() {return price;}public void setPrice(float price) {this.price = price;}}
4、在Product.hbm.xml中设置Category 多对一关系
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC"-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"><hibernate-mapping package="com.how2java.pojo"><class name="Product" table="product_"><id name="id" column="id"><generator class="native"></generator></id><property name="name" /><property name="price" /><!--name="category" 对应Product类中的category属性
class="Category" 表示对应Category类
column="cid" 表示指向 category_表的外键
--><many-to-one name="category" class="Category" column="cid" /></class></hibernate-mapping>
5、在hibernate.cfg.xml中增加Category的映射
<?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><!-- Database connection settings --><property name="connection.driver_class">com.mysql.jdbc.Driver</property><property name="connection.url">jdbc:mysql://localhost:3306/test?characterEncoding=GBK</property><property name="connection.username">root</property><property name="connection.password">admin</property><!-- SQL dialect --><property name="dialect">org.hibernate.dialect.MySQLDialect</property><property name="current_session_context_class">thread</property><property name="show_sql">true</property><property name="hbm2ddl.auto">update</property><mapping resource="com/how2java/pojo/Product.hbm.xml" /><mapping resource="com/how2java/pojo/Category.hbm.xml" /></session-factory></hibernate-configuration>
6、TestHibernate 测试many-to-one关系
package com.how2java.test;import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;import com.how2java.pojo.Category;
import com.how2java.pojo.Product;/*增加了一个新的Category对象"c1"
并将其设置为id=8的product的category*/
public class TestHibernate {public static void main(String[] args) {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s = sf.openSession();s.beginTransaction();Category c =new Category();c.setName("c1");s.save(c);Product p = (Product) s.get(Product.class, 8);p.setCategory(c);s.update(p);s.getTransaction().commit();s.close();sf.close();}
}

二、一对多

一个Product对应一个Category
一个Category对应多个Product 所以Category和Product是一对多的关系
获取id=1分类下的所有商品

1、为Category增加一个Set集合
package com.how2java.pojo;import java.util.Set;public class Category {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;}int id;String name;Set<Product> products;public Set<Product> getProducts() {return products;}public void setProducts(Set<Product> products) {this.products = products;}
}
2、为Category.hbm.xml增加one-to-many映射
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC"-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"><hibernate-mapping package="com.how2java.pojo"><class name="Category" table="category_"><id name="id" column="id"><generator class="native"></generator></id><property name="name" /><!--<set 用于设置一对多(多对多也是他)关系,也可以用list,设置稍复杂点,这里使用简单的set来入门。
name="products" 对应 Category类中的products属性
lazy="false" 表示不使用延迟加载。关于延迟加载,请参考关系的延迟加载
<key column="cid" not-null="false" /> 表示外键是cid,可以为空
<one-to-many class="Product" /> 表示一对多所对应的类是Product
--><set name="products" lazy="false"><key column="cid" not-null="false" /><one-to-many class="Product" /></set></class></hibernate-mapping>
3、TestHibernate 测试one-to-many关系
package com.how2java.test;import java.util.Set;import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;import com.how2java.pojo.Category;
import com.how2java.pojo.Product;/*首先获取id=1的category,然后通过getProducts() 直接取出其所对应的所有product*/
public class TestHibernate {public static void main(String[] args) {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s = sf.openSession();s.beginTransaction();Category c = (Category) s.get(Category.class, 1);Set<Product> ps = c.getProducts();for (Product p : ps) {System.out.println(p.getName());}s.getTransaction().commit();s.close();sf.close();}
}

三、多对多

一种Product可以被多个User购买
一个User可以购买多种Product 所以Product和User之间的关系是多对多 many-to-many
要实现多对多关系,必须有一张中间表 user_product 用于维护 User和Product之间的关系

User.java

package com.how2java.pojo;import java.util.Set;public class User {int id;String name;Set<Product> products;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 Set<Product> getProducts() {return products;}public void setProducts(Set<Product> products) {this.products = products;}
}

User.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC"-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"><hibernate-mapping package="com.how2java.pojo"><class name="User" table="user_"><id name="id" column="id"><generator class="native"></generator></id><property name="name" /><set name="products" table="user_product" lazy="false"><key column="uid" /><many-to-many column="pid" class="Product" /></set>       </class></hibernate-mapping>

Product.java
增加了对应Users的集合

package com.how2java.pojo;import java.util.Set;public class Product {int id;String name;float price;Category category;Set<User> users;public Set<User> getUsers() {return users;}public void setUsers(Set<User> users) {this.users = users;}public Category getCategory() {return category;}public void setCategory(Category category) {this.category = category;}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 float getPrice() {return price;}public void setPrice(float price) {this.price = price;}}

Product.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC"-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"><hibernate-mapping package="com.how2java.pojo"><class name="Product" table="product_"><id name="id" column="id"><generator class="native"></generator></id><property name="name" /><property name="price" /><many-to-one name="category" class="Category" column="cid" /><set name="users" table="user_product" lazy="false"><key column="pid" /><many-to-many column="uid" class="User" /></set>       </class></hibernate-mapping>
在hibernate.cfg.xml中增加User的映射
<?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><!-- Database connection settings --><property name="connection.driver_class">com.mysql.jdbc.Driver</property><property name="connection.url">jdbc:mysql://localhost:3306/test?characterEncoding=GBK</property><property name="connection.username">root</property><property name="connection.password">admin</property><!-- SQL dialect --><property name="dialect">org.hibernate.dialect.MySQLDialect</property><property name="current_session_context_class">thread</property><property name="show_sql">true</property><property name="hbm2ddl.auto">update</property><mapping resource="com/how2java/pojo/Product.hbm.xml" /><mapping resource="com/how2java/pojo/Category.hbm.xml" /><mapping resource="com/how2java/pojo/User.hbm.xml" /></session-factory></hibernate-configuration>
TestHibernate 测试many-to-many关系
package com.how2java.test;import java.util.HashSet;
import java.util.Set;import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;import com.how2java.pojo.Product;
import com.how2java.pojo.User;/*首先增加3个用户
然后演示产品1被用户1,2,3购买*/
public class TestHibernate {public static void main(String[] args) {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s = sf.openSession();s.beginTransaction();//增加3个用户Set<User> users = new HashSet();for (int i = 0; i < 3; i++) {User u =new User();u.setName("user"+i);users.add(u);s.save(u);}//产品1被用户1,2,3购买Product p1 = (Product) s.get(Product.class, 1);p1.setUsers(users);s.save(p1);s.getTransaction().commit();s.close();sf.close();}
}

各类概念

一、事务

Hibernate的任何对数据有改动的操作,都应该被放在事务里面.
在事务中的多个操作行为,要么都成功,要么都失败
  1. hibernate中的事务由s.beginTransaction();开始
  2. 由s.getTransaction().commit();结束
本例子,执行了两个操作
第一个,删除id=1的产品,这个是会成功的
第二个,修改id=2的产品,使得其产品名称超过了数据库中设置的长度30,这个是会失败的。
因为这两个操作都是在一个事务中,而且第二个操作失败了,所以最后的结果是两个操作都没有生效
package com.how2java.test;import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import com.how2java.pojo.Product;/*在同一个事务中做了两件事情
1. 删除id=1的产品
2. 修改id=2的产品,使得其产品名称超过了数据库中设置的长度30.
提交事务。第二个任务失败了,但是因为在同一个事务中,所以第一个任务也没有生效。因此id=1的产品,依然保留下来了。*/public class TestHibernate {public static void main(String[] args) {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s = sf.openSession();s.beginTransaction();Product p = (Product) s.get(Product.class, 1);s.delete(p);Product p2 = (Product) s.get(Product.class, 2);p2.setName("长度超过30的字符串作为产品名称长度超过30的字符串作为产品名称长度超过30的字符串作为产品名称长度超过30的字符串作为产品名称");s.update(p2);s.getTransaction().commit();s.close();sf.close();}
}

注:MYSQL 表的类型必须是INNODB才支持事务

在Mysql中,只有当表的类型是INNODB的时候,才支持事务,所以需要把表的类型设置为INNODB,否则无法观察到事务.

修改表的类型为INNODB的SQL:alter table product_ ENGINE  = innodb;
查看表的类型的SQLshow table status from test;

不过有个前提,就是当前的MYSQL服务器本身要支持INNODB

二、属性延迟加载

hibernate中的延迟加载(lazyload)分属性的延迟加载和关系的延迟加载 属性的延迟加载:
当使用load的方式来获取对象的时候,只有访问了这个对象的属性,hibernate才会到数据库中进行查询。否则不会访问数据库
package com.how2java.test;import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;import com.how2java.pojo.Product;/*在打印log1之前,是不会打印出sql语句的,只有在访问属性“getName()"的时候,才会访问数据库*/public class TestHibernate {public static void main(String[] args) {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s = sf.openSession();s.beginTransaction();Product p = (Product)s.load(Product.class, 1);System.out.println("log1");System.out.println(p.getName());System.out.println("log2");s.getTransaction().commit();s.close();sf.close();}
}

三、关系延迟加载

延迟加载又叫lazyload,在one-many many-many的时候都可以使用关系的延迟加载
<set name="products" lazy="false">

改为

<set name="products" lazy="true">

表示通过Category获取产品是延迟加载的

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC"-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"><hibernate-mapping package="com.how2java.pojo"><class name="Category" table="category_"><id name="id" column="id"><generator class="native"></generator></id><property name="name" /><set name="products" lazy="true"><key column="cid" not-null="false" /><one-to-many class="Product" /></set></class></hibernate-mapping>
package com.how2java.test;import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;import com.how2java.pojo.Category;public class TestHibernate {public static void main(String[] args) {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s = sf.openSession();s.beginTransaction();Category c = (Category) s.get(Category.class, 1);System.out.println("log1");System.out.println(c.getProducts());System.out.println("log1");s.getTransaction().commit();s.close();sf.close();}
}

执行15行的时候,只会查询Category表的信息,不会查询product_表

只有在执行18行,通过category取products的时候,才会进行对product_表的查询

三、级联

什么是级联?
简单的说,没有配置级联的时候,删除分类,其对应的产品不会被删除。
但是如果配置了恰当的级联,那么删除分类的时候,其对应的产品都会被删除掉。包括上一步说的删除用得级联,级联有4种类型:
all:所有操作都执行级联操作;
none:所有操作都不执行级联操作;
delete:删除时执行级联操作;
save-update:保存和更新时执行级联操作;
级联通常用在one-many和many-to-many上,几乎不用在many-one上。
delete 级联

在一对多代码的基础之上,修改TestHibernate类为

Category c = (Category) s.get(Category.class, 3);
s.delete(c);

并且为Category.hbm.xml 加上

<set name="products" cascade="delete" lazy="false">

运行代码就会发现,删除分类的时候,会把分类下对应的产品都删除掉,否则只会把产品对应的cid设置为空
Category.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC"-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"><hibernate-mapping package="com.how2java.pojo"><class name="Category" table="category_"><id name="id" column="id"><generator class="native"></generator></id><property name="name" /><set name="products" cascade="delete" lazy="false"><key column="cid" not-null="false" /><one-to-many class="Product" /></set></class></hibernate-mapping>

TestHibernate.java

package com.how2java.test;import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;import com.how2java.pojo.Category;public class TestHibernate {public static void main(String[] args) {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s = sf.openSession();s.beginTransaction();Category c = (Category) s.get(Category.class, 3);s.delete(c);s.getTransaction().commit();s.close();sf.close();}
}

save-update 级联

在一对多代码的基础之上,修改TestHibernate类为

Category c = (Category) s.get(Category.class, 5);
Product p1 = new Product();
p1.setName("product_501");
Product p2 = new Product();
p2.setName("product_502");
Product p3 = new Product();
p3.setName("product_503");

并且为Category.hbm.xml 加上

<set name="products" cascade="save-update" lazy="false">

运行代码就会发现,这3个瞬时状态的产品对象虽然没有添加到数据库里,但是在事务提交的时候,会把他们3个持久化。 如果没有cascade=“save-update”,就会报错

Category.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC"-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"><hibernate-mapping package="com.how2java.pojo"><class name="Category" table="category_"><id name="id" column="id"><generator class="native"></generator></id><property name="name" /><set name="products" cascade="save-update" lazy="false"><key column="cid" not-null="false" /><one-to-many class="Product" /></set></class></hibernate-mapping>

TestHibernate.java

package com.how2java.test;import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;import com.how2java.pojo.Category;
import com.how2java.pojo.Product;public class TestHibernate {public static void main(String[] args) {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s = sf.openSession();s.beginTransaction();Category c = (Category) s.get(Category.class, 5);Product p1 = new Product();p1.setName("product_501");Product p2 = new Product();p2.setName("product_502");Product p3 = new Product();p3.setName("product_503");c.getProducts().add(p1);c.getProducts().add(p2);c.getProducts().add(p3);s.getTransaction().commit();s.close();sf.close();}public static void main4delete(String[] args) {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s = sf.openSession();s.beginTransaction();Category c = (Category) s.get(Category.class, 3);s.delete(c);s.getTransaction().commit();s.close();sf.close();}
}
all和none级联
all 就是 delete+save-update
none 就是没有,默认就是none

四、一级缓存

hibernate默认是开启一级缓存的,一级缓存存放在session上
package com.how2java.test;import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;import com.how2java.pojo.Category;/*第一次通过id=1获取对象的时候,session中是没有对应缓存对象的,所以会在"log1"后出现sql查询语句。
第二次通过id=1获取对象的时候,session中有对应的缓存对象,所以在"log2"后不会出现sql查询语句*/
public class TestHibernate {public static void main(String[] args) {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s = sf.openSession();s.beginTransaction();System.out.println("log1");Category c1 = (Category)s.get(Category.class, 1);System.out.println("log2");Category c2= (Category)s.get(Category.class, 1);System.out.println("log3");       s.getTransaction().commit();s.close();sf.close();}
}

所以总共会看到一次SQL语句出现

五、二级缓存

Hibernate的一级缓存是在Session上,二级缓存是在SessionFactory上
package com.how2java.test;import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;import com.how2java.pojo.Category;/*创建了两个Session
在第一个Session里
第一次获取id=1的Category 会执行SQL语句
第二次获取id=1的Category,不会执行SQL语句,因为有一级缓存
在第二个Session里
获取id=1的Category,会执行SQL语句,因为在第二个Session,没有缓存该对象。
所以总共会看到两条SQL语句。*/
public class TestHibernate {public static void main(String[] args) {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s = sf.openSession();s.beginTransaction();Category p1 = (Category) s.get(Category.class, 1);Category p2 = (Category) s.get(Category.class, 1);s.getTransaction().commit();s.close();Session s2 = sf.openSession();s2.beginTransaction();Category p3 = (Category) s2.get(Category.class, 1);s2.getTransaction().commit();s2.close();sf.close();}
}

hibernate.cfg.xml 中增加对二级缓存的配置

在hibernate.cfg.xml中开启二级缓存的配置
hibernate本身不提供二级缓存,都是使用第三方的二级缓存插件
这里使用的是 EhCache提供的二级缓存

<?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><!-- Database connection settings --><property name="connection.driver_class">com.mysql.jdbc.Driver</property><property name="connection.url">jdbc:mysql://localhost:3306/test?characterEncoding=GBK</property><property name="connection.username">root</property><property name="connection.password">admin</property><!-- SQL dialect --><property name="dialect">org.hibernate.dialect.MySQLDialect</property><property name="current_session_context_class">thread</property><property name="show_sql">true</property><property name="hbm2ddl.auto">update</property><!--二级缓存--><property name="hibernate.cache.use_second_level_cache">true</property><property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property><mapping resource="com/how2java/pojo/Product.hbm.xml" /><mapping resource="com/how2java/pojo/Category.hbm.xml" /><mapping resource="com/how2java/pojo/User.hbm.xml" /></session-factory></hibernate-configuration>
创建一个ehcache.xml用于EHCache的缓存配置
<ehcache><diskStore path="java.io.tmpdir"/><defaultCachemaxElementsInMemory="10000"eternal="false"timeToIdleSeconds="120"timeToLiveSeconds="120"overflowToDisk="true"/>
</ehcache>
Category.hbm.xml

对于要进行二级缓存的实体类,进行配置,增加

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC"-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"><hibernate-mapping package="com.how2java.pojo"><class name="Category" table="category_"><cache usage="read-only" /><id name="id" column="id"><generator class="native"></generator></id><property name="name" /><set name="products" lazy="true"><key column="cid" not-null="false" /><one-to-many class="Product" /></set></class></hibernate-mapping>
测试效果
package com.how2java.test;import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;import com.how2java.pojo.Category;/*使用不同的session,都去获取id=1的category,只会访问一次数据库。因为第二次获取虽然没有从第二个session中拿到缓存,但是从sessionfactory中拿到了Category缓存对象*/
public class TestHibernate {public static void main(String[] args) {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s = sf.openSession();s.beginTransaction();Category c1 = (Category)s.get(Category.class, 1);System.out.println("log1");Category c2= (Category)s.get(Category.class, 1);System.out.println("log2");s.getTransaction().commit();s.close();Session s2 = sf.openSession();s2.beginTransaction();Category c3 = (Category)s2.get(Category.class, 1);System.out.println("log3");s2.getTransaction().commit();s2.close();sf.close();}
}

七、分页

使用Criteria进行分页查询

无论你使用的是Oracle,Mysql,NoSQL还是DB2,分页查询的代码写法都是一样的

package com.how2java.test;import java.util.List;import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.criterion.Restrictions;import com.how2java.pojo.Product;/*Hibernate使用Criteria 来进行分页查询
c.setFirstResult(2); 表示从第3条数据开始
c.setMaxResults(5); 表示一共查询5条数据*/
public class TestHibernate {public static void main(String[] args) {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s = sf.openSession();s.beginTransaction();String name = "iphone";Criteria c= s.createCriteria(Product.class);c.add(Restrictions.like("name", "%"+name+"%"));c.setFirstResult(2);c.setMaxResults(5);List<Product> ps = c.list();for (Product p : ps) {System.out.println(p.getName());}s.getTransaction().commit();s.close();sf.close();}
}

八、两种获取方式

通过id获取Product对象有两种方式,分别是get和load
他们的区别分别在于
1. 延迟加载
2. 对于id不存在的时候的处理
延迟加载
package com.how2java.test;import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;import com.how2java.pojo.Product;/*load方式是延迟加载,只有属性被访问的时候才会调用sql语句
get方式是非延迟加载,无论后面的代码是否会访问到属性,马上执行sql语句*/
public class TestHibernate {public static void main(String[] args) {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s = sf.openSession();s.beginTransaction();System.out.println("log1");Product p = (Product) s.get(Product.class, 1);System.out.println("log2");Product p2 = (Product) s.load(Product.class, 2);System.out.println("log3");System.out.println(p2.getName());System.out.println("log4");s.getTransaction().commit();s.close();sf.close();}
}
对于id不存在的对象的处理
package com.how2java.test;import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;import com.how2java.pojo.Product;/*都通过id=500去获取对象
1. get方式会返回null
2. load方式会抛出异常*/
public class TestHibernate {public static void main(String[] args) {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s = sf.openSession();s.beginTransaction();System.out.println("log1");Product p = (Product)s.get(Product.class, 5);System.out.println("log2");Product p2 = (Product)s.load(Product.class, 5);System.out.println("log3");Product p3 = (Product)s.get(Product.class, 500);System.out.println("p3="+p3);Product p4 = (Product)s.load(Product.class, 500);System.out.println("p3="+p4);s.getTransaction().commit();s.close();sf.close();}
}

九、两种session方式

Hibernate有两种方式获得session,分别是:
openSession和getCurrentSession
他们的区别在于
1. 获取的是否是同一个session对象
openSession每次都会得到一个新的Session对象
getCurrentSession在同一个线程中,每次都是获取相同的Session对象,但是在不同的线程中获取的是不同的Session对象
2. 事务提交的必要性
openSession只有在增加,删除,修改的时候需要事务,查询时不需要的
getCurrentSession是所有操作都必须放在事务中进行,并且提交事务后,session就自动关闭,不能够再进行关闭
OpenSession每次都会得到一个新的Session对象
package com.how2java.test;import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;/*OpenSession每次都会得到一个新的Session对象,所以System.out.println(s1==s2);会打印false*/
public class TestHibernate {public static void main(String[] args) {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s1 = sf.openSession();Session s2 = sf.openSession();System.out.println(s1==s2);s1.close();s2.close();sf.close();}
}

相同线程的getCurrentSession
package com.how2java.test;import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;/*如果是同一个线程(本例是在主线程里),每次获取的都是相同的Session*/
public class TestHibernate {public static void main(String[] args) {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s1 = sf.getCurrentSession();Session s2 = sf.getCurrentSession();System.out.println(s1 == s2);s1.close();
//      s2.close();sf.close();}
}

不同线程的getCurrentSession
package com.how2java.test;import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;/*如果是不同线程,每次获取的都是不同的Session*/
public class TestHibernate {static Session s1;static Session s2;public static void main(String[] args) throws InterruptedException {final SessionFactory sf = new Configuration().configure().buildSessionFactory();Thread t1 = new Thread() {public void run() {s1 = sf.getCurrentSession();}};t1.start();Thread t2 = new Thread() {public void run() {s2 = sf.getCurrentSession();}};t2.start();t1.join();t2.join();System.out.println(s1 == s2);}}

openSession查询时候不需要事务
package com.how2java.test;import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;import com.how2java.pojo.Product;/*如果是做增加,修改,删除是必须放在事务里进行的。 但是如果是查询或者get,那么对于openSession而言就不需要放在事务中进行*/
public class TestHibernate {static Session s1;static Session s2;public static void main(String[] args) throws InterruptedException {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s1 = sf.openSession();s1.get(Product.class, 5);s1.close();sf.close();}
}
getCurrentSession所有操作都必须放在事务中
package com.how2java.test;import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;import com.how2java.pojo.Product;public class TestHibernate {public static void main(String[] args) throws InterruptedException {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s1 = sf.getCurrentSession();s1.get(Product.class, 5);s1.close();sf.close();}}

对于getCurrentSession而言所有操作都必须放在事务中,甚至于查询和get都需要事务。
16行的get没有放在事务中,就会导致异常产生

getCurrentSession在提交事务后,session自动关闭
package com.how2java.test;import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;import com.how2java.pojo.Product;public class TestHibernate {public static void main(String[] args) throws InterruptedException {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s1 = sf.getCurrentSession();s1.beginTransaction();s1.get(Product.class, 5);s1.getTransaction().commit();s1.close();sf.close();}}

22行,在事务关闭后,试图关闭session,就会报session已经关闭的异常

十、N+1

Hibernate有缓存机制,可以通过用id作为key把product对象保存在缓存中 同时hibernate也提供Query的查询方式。假设数据库中有100条记录,其中有30条记录在缓存中,但是使用Query的list方法,就会所有的100条数据都从数据库中查询,而无视这30条缓存中的记录 N+1是什么意思呢,首先执行一条sql语句,去查询这100条记录,但是,只返回这100条记录的ID
然后再根据id,进行进一步查询。 如果id在缓存中,就从缓存中获取product对象了,否则再从数据库中获取
Hibernate使用Iterator实现N 1
package com.how2java.test;import java.util.Iterator;import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;import com.how2java.pojo.Product;/*首先通过Query的iterator把所有满足条件的Product的id查出来然后再通过it.next()查询每一个对象
如果这个对象在缓存中,就直接从缓存中取了
否则就从数据库中获取N+1中的1,就是指只返回id的SQL语句,N指的是如果在缓存中找不到对应的数据,就到数据库中去查*/
public class TestHibernate {public static void main(String[] args) {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s = sf.openSession();s.beginTransaction();String name = "iphone";Query q =s.createQuery("from Product p where p.name like ?");q.setString(0, "%"+name+"%");Iterator<Product> it= q.iterate();while(it.hasNext()){Product p =it.next();System.out.println(p.getName());}s.getTransaction().commit();s.close();sf.close();}}

十一、查询总数

返回满足条件的总数

首先还是准备一个有统计函数的语句

select count(*) from ....

根据这条SQL语句创建一个Query对象,调用Query对象的uniqueResult()方法,返回一个long型的数据,即查询总数。

package com.how2java.test;import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;public class TestHibernate {public static void main(String[] args) {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s = sf.openSession();s.beginTransaction();String name = "iphone";Query q =s.createQuery("select count(*) from Product p where p.name like ?");q.setString(0, "%"+name+"%");long total= (Long) q.uniqueResult();System.out.println(total);s.getTransaction().commit();s.close();sf.close();}}

十二、乐观锁

Hibernate使用乐观锁来处理脏数据问题

首先看不使用乐观锁的情况

故意创造一个场景来制造脏数据。

  1. 通过session1得到id=1的对象 product1
  2. 在product1原来价格的基础上增加1000
  3. 更新product1之前,通过session2得到id=1的对象product2
  4. 在product2原来价格的基础上增加1000
  5. 更新product1
  6. 更新product2

最后结果是product的价格只增加了1000,而不是2000

package com.how2java.test;import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;import com.how2java.pojo.Product;public class TestHibernate {public static void main(String[] args) {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s1 = sf.openSession();Session s2 = sf.openSession();s1.beginTransaction();s2.beginTransaction();Product p1 = (Product) s1.get(Product.class, 1);System.out.println("产品原本价格是: " + p1.getPrice());p1.setPrice(p1.getPrice() + 1000);Product p2 = (Product) s2.get(Product.class, 1);p2.setPrice(p2.getPrice() + 1000);s1.update(p1);s2.update(p2);s1.getTransaction().commit();s2.getTransaction().commit();Product p = (Product) s1.get(Product.class, 1);System.out.println("经过两次价格增加后,价格变为: " + p.getPrice());s1.close();s2.close();sf.close();}}

修改配置文件 Product.hbm.xml
<version name="version" column="ver" type="int"></version>

增加一个version字段,用于版本信息控制。这就是乐观锁的核心机制。

比如session1获取product1的时候,version=1。 那么session1更新product1的时候,就需要确保version还是1才可以进行更新,并且更新结束后,把version改为2。

注意: version元素必须紧跟着id后面,否则会出错。

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC"-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"><hibernate-mapping package="com.how2java.pojo"><class name="Product" table="product_"><id name="id" column="id"><generator class="native"></generator></id><!--version元素必须紧挨着id后面  --><version name="version" column="ver" type="int"></version><property name="name" /><property name="price" /><many-to-one name="category" class="Category" column="cid" /><set name="users" table="user_product" lazy="false"><key column="pid" /><many-to-many column="uid" class="User" /></set></class></hibernate-mapping>
修改 Product.java
package com.how2java.pojo;import java.util.Set;public class Product {int id;String name;float price;Category category;int version;public int getVersion() {return version;}public void setVersion(int version) {this.version = version;}Set<User> users;public Set<User> getUsers() {return users;}public void setUsers(Set<User> users) {this.users = users;}public Category getCategory() {return category;}public void setCategory(Category category) {this.category = category;}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 float getPrice() {return price;}public void setPrice(float price) {this.price = price;}}
重新运行一样的代码
package com.how2java.test;import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;import com.how2java.pojo.Product;public class TestHibernate {public static void main(String[] args) {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s1 = sf.openSession();Session s2 = sf.openSession();s1.beginTransaction();s2.beginTransaction();Product p1 = (Product) s1.get(Product.class, 1);System.out.println("产品原本价格是: " + p1.getPrice());p1.setPrice(p1.getPrice() + 1000);Product p2 = (Product) s2.get(Product.class, 1);p2.setPrice(p2.getPrice() + 1000);s1.update(p1);s2.update(p2);s1.getTransaction().commit();s2.getTransaction().commit();Product p = (Product) s1.get(Product.class, 1);System.out.println("经过两次价格增加后,价格变为: " + p.getPrice());s1.close();s2.close();sf.close();}}

做同样的业务就会抛出异常,提示该行已经被其他事务删除或者修改过了,本次修改无法生效。

这样就保证了数据的一致性。

原理
  1. 假设数据库中产品的价格是10000,version是10
  2. session1,session2分别获取了该对象
  3. 都修改了对象的价格
  4. session1试图保存到数据库,检测version依旧=10,成功保存,并把version修改为11
  5. session2试图保存到数据库,检测version=11,说明该数据已经被其他人动过了。 保存失败,抛出异常

十三、C3P0连接池

建立数据库连接时比较消耗时间的,所以通常都会采用数据库连接池的技术来建立多条数据库连接,并且在将来持续使用,从而节约掉建立数据库连接的时间
hibernate本身是提供了数据库连接池的,但是hibernate官网也不推荐使用他自带的数据库连接池。
一般都会使用第三方的数据库连接池
C3P0是免费的第三方的数据库连接池,并且有不错的表现
右边可以下载c3p0的jar包 注:当运行次数不大的时候,从运行效果上来看,是看不出区别的。 只有在高并发量的情况下,才会体会出来。本知识主要是提供这个相关配置办法,以供以后有需要的时候,查询与修改方便。
1、jar包
2、进行c3p0连接池的配置

加上相应的配置即可,代码无需做任何改动

<?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><!-- Database connection settings --><property name="connection.driver_class">com.mysql.jdbc.Driver</property><property name="connection.url">jdbc:mysql://localhost:3306/test?characterEncoding=GBK</property><property name="connection.username">root</property><property name="connection.password">admin</property><!-- SQL dialect --><property name="dialect">org.hibernate.dialect.MySQLDialect</property><property name="current_session_context_class">thread</property><property name="show_sql">true</property><property name="hbm2ddl.auto">update</property><!--配置连接池--><property name="hibernate.connection.provider_class"> org.hibernate.connection.C3P0ConnectionProvider </property> <property name="hibernate.c3p0.max_size">20</property> <property name="hibernate.c3p0.min_size">5</property> <property name="hibernate.c3p0.timeout">50000</property> <property name="hibernate.c3p0.max_statements">100</property> <property name="hibernate.c3p0.idle_test_period">3000</property> <!-- 当连接池耗尽并接到获得连接的请求,则新增加连接的数量 --><property name="hibernate.c3p0.acquire_increment">2</property> <!-- 是否验证,检查连接 --><property name="hibernate.c3p0.validate">false</property>           <mapping resource="com/how2java/pojo/Product.hbm.xml" /><mapping resource="com/how2java/pojo/Category.hbm.xml" /><mapping resource="com/how2java/pojo/User.hbm.xml" /></session-factory></hibernate-configuration>
Category.hbm.xml

记得要把上一步的二级缓存的相关配置去掉

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC"-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"><hibernate-mapping package="com.how2java.pojo"><class name="Category" table="category_"><!--配置连接池需要取消二级缓存-->
<!--     <cache usage="read-only" />--><id name="id" column="id"><generator class="native"></generator></id><property name="name" /><set name="products" lazy="true"><key column="cid" not-null="false" /><one-to-many class="Product" /></set></class></hibernate-mapping>

注解

一、示例

Hibernate的注解是什么?

简单的说,本来放在hbm.xml文件里的映射信息,现在不用配置文件做了,改由注解来完成

Product.hbm.xml

这是Product.hbm.xml,用于提供类与表的映射,以及属性与表字段的映射关系

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC"-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"><hibernate-mapping package="com.how2java.pojo"><class name="Product" table="product_"><id name="id" column="id"><generator class="native"></generator></id><property name="name" /><property name="price" /></class></hibernate-mapping>
注解方式

使用注解之后的Product.java

package com.how2java.pojo;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;/*现在直接在类上使用注解,来达到相同的配置效果。*/@Entity
@Table(name = "product_")
public class Product {int id;String name;float price;@Id@GeneratedValue(strategy = GenerationType.IDENTITY)@Column(name = "id")  public int getId() {return id;}public void setId(int id) {this.id = id;}@Column(name = "name")public String getName() {return name;}public void setName(String name) {this.name = name;}@Column(name = "price")public float getPrice() {return price;}public void setPrice(float price) {this.price = price;}}
hibernate.cfg.xml 配置文件改动

为了能够让hibernate支持这种注解的方式,还需要做一个改动:
把hibernate.cfg.xml配置文件中的

<mapping resource="com/how2java/pojo/Product.hbm.xml" />

注释掉,采用:

<mapping class="com.how2java.pojo.Product" />

这种写法,其他所有代码都不用改变,这样就可以一样实现hibernate的CRUD操作

<?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><!-- Database connection settings --><property name="connection.driver_class">com.mysql.jdbc.Driver</property><property name="connection.url">jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8</property><property name="connection.characterEncoding">utf-8</property><property name="connection.username">root</property><property name="connection.password">admin</property><!-- SQL dialect --><property name="dialect">org.hibernate.dialect.MySQLDialect</property><property name="current_session_context_class">thread</property><property name="show_sql">true</property><property name="hbm2ddl.auto">update</property>
<!--    <mapping resource="com/how2java/pojo/Product.hbm.xml" /> --><mapping class="com.how2java.pojo.Product" /></session-factory></hibernate-configuration>

二、类与属性

1、hibernate 注解分类

hibernate里常用注解包括,类注解,属性注解,关系注解,其他的注解

2、类注解

在注解示例-注解方式的Product中,Product类声明前面有两个注解:
@Entity 和 @Table(name = "product_")
@Entity 表示这是一个实体类,用于映射表
@Table(name = "product_") 表示这是一个类,映射到的表名:product_

示例:

@Entity
@Table(name = "product_")
public class Product {int id;String name;float price;
}

3、属性注解

然后是属性注解,属性注解是配置在属性对应的getter方法上的

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
public int getId() {return id;
}

@Id 表示这是主键
@GeneratedValue(strategy = GenerationType.IDENTITY) 表示自增长方式使用mysql自带的
@Column(name = “id”) 表示映射到字段id

@Column(name = "name")
public String getName() {return name;
}

表示name属性映射表的name字段

@Column(name = "price")
public float getPrice() {return price;
}

表示price属性映射表的price字段

package com.how2java.pojo;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;@Entity
@Table(name = "product_")
public class Product {int id;String name;float price;@Id@GeneratedValue(strategy = GenerationType.IDENTITY)@Column(name = "id")  public int getId() {return id;}public void setId(int id) {this.id = id;}@Column(name = "name")public String getName() {return name;}public void setName(String name) {this.name = name;}@Column(name = "price")public float getPrice() {return price;}public void setPrice(float price) {this.price = price;}}

三、关系

1、多对一注解

把多对一改成用注解来实现

  1. 把Category的id和name字段改为支持注解

注: 分类的getName上并没有加上@Column(name=“name”),也可以达到映射的效果。 因为getName方法默认会被认为是字段映射。 除非加上了@Transient 才表示不进行映射
2. 把Product的getCategory进行多对一映射

@ManyToOne@JoinColumn(name="cid") public Category getCategory() {return category;}

@ManyToOne 表示多对一关系
@JoinColumn(name=“cid”) 表示关系字段是cid
对比xml中的映射方式:

<many-to-one name="category" class="Category" column="cid" />
  1. 为hibernate.cfg.xml 添加Category的映射
<mapping class="com.how2java.pojo.Category" />

Category.java

package com.how2java.pojo;import javax.persistence.Column;import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;@Entity
@Table(name = "category_")
public class Category {int id;String name;@Id@GeneratedValue(strategy = GenerationType.IDENTITY)@Column(name = "id")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;}}

Produce.java

package com.how2java.pojo;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;@Entity
@Table(name = "product_")
public class Product {int id;String name;float price;Category category;@Id@GeneratedValue(strategy = GenerationType.IDENTITY)@Column(name = "id")  public int getId() {return id;}public void setId(int id) {this.id = id;}@Column(name = "name")public String getName() {return name;}public void setName(String name) {this.name = name;}@Column(name = "price")public float getPrice() {return price;}public void setPrice(float price) {this.price = price;}@ManyToOne@JoinColumn(name="cid")public Category getCategory() {return category;}public void setCategory(Category category) {this.category = category;}
}

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><!-- Database connection settings --><property name="connection.driver_class">com.mysql.jdbc.Driver</property><property name="connection.url">jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8</property><property name="connection.characterEncoding">utf-8</property><property name="connection.username">root</property><property name="connection.password">admin</property><!-- SQL dialect --><property name="dialect">org.hibernate.dialect.MySQLDialect</property><property name="current_session_context_class">thread</property><property name="show_sql">true</property><property name="hbm2ddl.auto">update</property>
<!--    <mapping resource="com/how2java/pojo/Product.hbm.xml" /> --><mapping class="com.how2java.pojo.Product" /><mapping class="com.how2java.pojo.Category" /></session-factory></hibernate-configuration>

二、一对多注解

在上一步的基础上做如下改动

  1. 为Category再加product集合,并提供getter和setter
Set<Product> products;public Set<Product> getProducts() {return products;}public void setProducts(Set<Product> products) {this.products = products;}
  1. 给getProducts方法加上一对多注解
@OneToMany(fetch=FetchType.EAGER)@JoinColumn(name="cid") public Set<Product> getProducts() {return products;}

@OneToMany 表示一对多,fetch=FetchType.EAGER 表示不进行延迟加载(FetchType.LAZY表示要进行延迟加载)
@JoinColumn(name=“cid”) 表示映射字段
对比xml中的映射方式:

    <set name="products" lazy="false"><key column="cid" not-null="false" /><one-to-many class="Product" /></set>
  1. 修改TestHibernate为

     SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s = sf.openSession();s.beginTransaction();Category c = (Category) s.get(Category.class, 1);s.getTransaction().commit();s.close();sf.close();Set<Product> ps = c.getProducts();for (Product p : ps) {System.out.println(p.getName());}
    

Category.java

package com.how2java.pojo;import java.util.Set;import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;@Entity
@Table(name = "category_")
public class Category {int id;String name;Set<Product> products;@Id@GeneratedValue(strategy = GenerationType.IDENTITY)@Column(name = "id")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;}@OneToMany(fetch=FetchType.EAGER)@JoinColumn(name="cid")public Set<Product> getProducts() {return products;}public void setProducts(Set<Product> products) {this.products = products;}
}

TestHibernate.java

package com.how2java.test;import java.util.Set;import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;import com.how2java.pojo.Category;
import com.how2java.pojo.Product;public class TestHibernate {public static void main(String[] args) {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s = sf.openSession();s.beginTransaction();Category c = (Category) s.get(Category.class, 1);s.getTransaction().commit();s.close();sf.close();Set<Product> ps = c.getProducts();for (Product p : ps) {System.out.println(p.getName());}}
}

3、多对多注解

  1. 在基于XML配置的多对多知识点的基础上进行多对多注解的修改

2.像上两步那样,为Product,User,Category 加上类和属性注解

  1. 加上多对一注解ManyToOne

  2. 加上一对多注解OneToMany

  3. ManyToMany
    为Product的getUsers加上

@ManyToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)@JoinTable(name="user_product",joinColumns=@JoinColumn(name="pid"),inverseJoinColumns=@JoinColumn(name="uid"))    public Set<User> getUsers() {return users;}

对比Product.hbm.xml中的配置:

   <set name="users" table="user_product" lazy="false"><key column="pid" /><many-to-many column="uid" class="User" /></set>

为User的getProducts加上

@ManyToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
@JoinTable(name="user_product",joinColumns=@JoinColumn(name="uid"),inverseJoinColumns=@JoinColumn(name="pid")
)
public Set<Product> getProducts() {return products;
}

对比User.hbm.xml中的配置

    <set name="products" table="user_product" lazy="false"><key column="uid" /><many-to-many column="pid" class="Product" /></set>
  1. hibernate.cfg.xml

     <mapping class="com.how2java.pojo.Product" /><mapping class="com.how2java.pojo.Category" /><mapping class="com.how2java.pojo.User" />
    

User.java

package com.how2java.pojo;import java.util.Set;import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;@Entity
@Table(name="user_")
public class User {int id;String name;Set<Product> products;@Id@GeneratedValue(strategy = GenerationType.IDENTITY)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;}@ManyToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)@JoinTable(name="user_product",joinColumns=@JoinColumn(name="uid"),inverseJoinColumns=@JoinColumn(name="pid"))   public Set<Product> getProducts() {return products;}public void setProducts(Set<Product> products) {this.products = products;}
}

Product.java

package com.how2java.pojo;import java.util.Set;import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.Table;@Entity
@Table(name="product_")
public class Product {int id;String name;float price;Category category;Set<User> users;@Id@GeneratedValue(strategy = GenerationType.IDENTITY)public int getId() {return id;}public void setId(int id) {this.id = id;}@ManyToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)@JoinTable(name="user_product",joinColumns=@JoinColumn(name="pid"),inverseJoinColumns=@JoinColumn(name="uid"))   public Set<User> getUsers() {return users;}public void setUsers(Set<User> users) {this.users = users;}@ManyToOne@JoinColumn(name="cid")    public Category getCategory() {return category;}public void setCategory(Category category) {this.category = category;}public String getName() {return name;}public void setName(String name) {this.name = name;}public float getPrice() {return price;}public void setPrice(float price) {this.price = price;}}

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><!-- Database connection settings --><property name="connection.driver_class">com.mysql.jdbc.Driver</property><property name="connection.url">jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8</property><property name="connection.characterEncoding">utf-8</property><property name="connection.username">root</property><property name="connection.password">admin</property><!-- SQL dialect --><property name="dialect">org.hibernate.dialect.MySQLDialect</property><property name="current_session_context_class">thread</property><property name="show_sql">true</property><property name="hbm2ddl.auto">update</property><mapping class="com.how2java.pojo.Product" /><mapping class="com.how2java.pojo.Category" /><mapping class="com.how2java.pojo.User" /></session-factory></hibernate-configuration>

TestHibernate.java

package com.how2java.test;import java.util.HashSet;
import java.util.Set;import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;import com.how2java.pojo.Product;
import com.how2java.pojo.User;public class TestHibernate {public static void main(String[] args) {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session s = sf.openSession();s.beginTransaction();//        //增加3个用户Set<User> users = new HashSet();for (int i = 0; i < 3; i++) {User u =new User();u.setName("user"+i);users.add(u);s.save(u);}//产品1被用户1,2,3购买Product p1 = (Product) s.get(Product.class, 1);p1.setUsers(users);s.getTransaction().commit();s.close();sf.close();}
}

四、注解手册

1、类相关注解

@Entity —— 将一个类声明为一个实体bean(即一个持久化POJO类)
@Table —— 注解声明了该实体bean映射指定的表(table),目录(catalog)和schema的名字

2、属性相关注解

@Id —— 注解声明了该实体bean的标识属性(对应表中的主键)。
@Column —— 注解声明了属性到列的映射。该注解有如下的属性
name 可选,列名(默认值是属性名)
unique 可选,是否在该列上设置唯一约束(默认值false)
nullable 可选,是否设置该列的值可以为空(默认值false)
insertable 可选,该列是否作为生成的insert语句中的一个列(默认值true)
updatable 可选,该列是否作为生成的update语句中的一个列(默认值true)
columnDefinition 可选,为这个特定列覆盖sql ddl片段(这可能导致无法在不同数据库间移植)
table 可选,定义对应的表(默认为主表)
length 可选,列长度(默认值255)
precision 可选,列十进制精度(decimal precision)(默认值0)
scale 可选,如果列十进制数值范围(decimal scale)可用,在此设置(默认值0)
@GeneratedValue —— 注解声明了主键的生成策略。该注解有如下属性
strategy 指定生成的策略(JPA定义的),这是一个GenerationType。默认是GenerationType. AUTO
GenerationType.AUTO 主键由程序控制
GenerationType.TABLE 使用一个特定的数据库表格来保存主键
GenerationType.IDENTITY 主键由数据库自动生成(主要是自动增长类型)
GenerationType.SEQUENCE 根据底层数据库的序列来生成主键,条件是数据库支持序列。(这个值要与generator一起使用)
generator 指定生成主键使用的生成器(可能是orcale中的序列)。
@SequenceGenerator —— 注解声明了一个数据库序列。该注解有如下属性
name 表示该表主键生成策略名称,它被引用在@GeneratedValue中设置的“gernerator”值中
sequenceName 表示生成策略用到的数据库序列名称。
initialValue 表示主键初始值,默认为0.
allocationSize 每次主键值增加的大小,例如设置成1,则表示每次创建新记录后自动加1,默认为50.

3、关系相关注解

@ManyToOne 设置多对一关联
方法一
@ManyToOne(cascade={CasCadeType.PERSIST,CascadeType.MERGE})
@JoinColumn(name="外键")
public 主表类 get主表类(){return 主表对象}
方法二
@ManyToOne(cascade={CascadeType.PERSIST,CascadeType.MERGE})
@JoinTable(name="关联表名",
joinColumns = @JoinColumn(name="主表外键"),
inverseJoinColumns = @JoinColumns(name="从表外键")
)
@OneToMany 设置一对多关联。
方法一 。
“一端”配置
@OneToMany(mappedBy="“多端”的属性")
public List<“多端”类> get“多端”列表(){return “多端”列表}
“多端”配置参考@ManyToOne.
方法二
“一端”配置
@OneToMany(mappedBy="“多端”的属性")
@MapKey(name="“多端”做为Key的属性")
public Map<“多端”做为Key的属性的类,主表类> get“多端”列表(){return “多端”列表}
“多端”配置参考@ManyToOne.
方法三 使用这种配置,在为“一端”添加“多端”时,可以修改“多端”的外键。
“一端”配置
@OneToMany
@JoinColumn(name="“多端”外键")
public List<“多端”类> get“多端”列表(){return “多端”列表}
“多端”配置参考@ManyToOne.

Hibernate教程——我的笔记相关推荐

  1. 26Play框架教程2学习笔记

    Play框架教程2学习笔记 文章目录 1 play框架01 1.1 概述 1.2 特性 1.2.1 无缝集成现有开发环境 1.2.2 热重载和修改Bug 1.2.3 简单的无状态MVC架构 1.2.4 ...

  2. 《C#图解教程》读书笔记之四:类和继承

    本篇已收录至<C#图解教程>读书笔记目录贴,点击访问该目录可获取更多内容. 一.万物之宗:Object (1)除了特殊的Object类,其他所有类都是派生类,即使他们没有显示基类定义. ( ...

  3. python编程16章教程_Python学习笔记__16.2章 TCP编程

    # 这是学习廖雪峰老师python教程的学习笔记 Socket是网络编程的一个抽象概念.通常我们用一个Socket表示"打开了一个网络链接",而打开一个Socket需要知道目标计算 ...

  4. 前端获取div里面的标签_web前端教程JavaScript学习笔记DOM

    web前端教程JavaScript学习笔记 DOM一DOM(Document Object Model): 文档对象模型 其实就是操作 html 中的标签的一些能力 我们可以操作哪些内容 获取一个元素 ...

  5. 《C#图解教程》读书笔记之六:接口和转换

    本篇已收录至<C#图解教程>读书笔记目录贴,点击访问该目录可获取更多内容. 一.接口那点事儿 (1)什么是接口? 一组函数成员而未实现的引用类型.只有类和结构能实现接口. (2)从ICom ...

  6. hibernate教程_Hibernate多对多教程

    hibernate教程 介绍: 在本教程中,我们将学习使用Hibernate @ManyToMany注释定义和使用多对多实体关联. 上下文构建: 为了继续学习本教程,我们假设我们有两个实体– 雇员和资 ...

  7. Hibernate教程– ULTIMATE指南(PDF下载)

    编者注:在本文中,我们提供了全面的Hibernate教程. Hibernate ORM(简称Hibernate)是一个对象关系映射框架,它有助于将面向对象的域模型转换为传统的关系数据库. Hibern ...

  8. Hibernate教程

    Hibernate教程 最近我写了很多hibernate教程.Hibernate是当前市场上最好的Java ORM工具之一.所以这篇文章就像是hibernate教程和示例的所有帖子的索引.您可以按顺序 ...

  9. hibernate教程_Hibernate教程

    hibernate教程 Recently I have written a lot of hibernate tutorial. Hibernate is one of the best Java O ...

  10. matlab初学者教程_初学者的Hibernate教程

    matlab初学者教程 Welcome to the Hibernate tutorial for Beginners. Hibernate is one of the most widely use ...

最新文章

  1. cocoapods更新
  2. 个人所得税计算器2016 by Jacksile
  3. 急我所需!机器学习、深度学习绘图模板.ppt
  4. window.location.reload() 刷新页面时,如何不弹出提示框
  5. Java中SeparatedListAdapter类的实现
  6. Oracle 11g 中告警日志的位置
  7. linux中使用u盘和光驱的命令_Linux文件操作高频使用命令
  8. DOCKER - 容器抓包
  9. python转r字符_python r不转义变量
  10. SPSS 17.0中文版常用功能与应用实例精讲
  11. 计算机网络领悟摩尔定,计算机网络等133信息技术展望P15-P17.PPT
  12. windows全部启动项
  13. libiconv_百度百科
  14. 深度可分离卷积解析 - MobileNetV1
  15. 因为intel显卡和nvidia显卡驱动不兼容造成的ubuntu系统循环登录和黑屏问题解决方法
  16. Java POI 设置字体下划线、方框打勾、字体加粗
  17. 谷歌金融 Onebox 实现实时信息更新
  18. 看院线电影就用移动电影院V2.0App
  19. 微信小程序爱江山更爱美人忘记服务器,爱江山更爱美人微信小程序
  20. 微信小程序开发:自定义组件-behaviors

热门文章

  1. 使用微信机器人实现华为OLT和中兴OLT挂测的简单功能
  2. CDKEY制作:为什么会有CDKEY产生机这样的破解工具?
  3. echarts-市地图
  4. python核心编程:入门Python编程的8个实践性建议
  5. 《高质量程序设计指南:C++/C语言》 林锐
  6. 《高质量程序设计指南——C++/C》重印啦!
  7. 学生选课管理系统php,学生选课管理系统(全源代码.doc
  8. java反编译工具--jd-gui
  9. Pycharm导入python项目
  10. Spark SQL从入门到精通