Hibernate框架的应用背景:
使用JDBC做数据库相关功能开发会做很多重复性的工作,比如创建连接,关闭连接,把字段逐一映射到属性中。 Hibernate把这一切都封装起来了,使得数据库访问变得轻松而简单,代码也更加容易维护。
HelloWorld基础:
- 准备好数据库和创建好数据表。
- 创建一个java project
- 导入相关的依赖jar包(hibernate不同版本之间的jar包存在兼容性问题,所以要保证版本一致性和兼容性)也可以自行从官网上下载最新版本。hibernate.rar :http://download.how2j.cn/308/hibernate.rar lib.rar:http://download.how2j.cn/57/lib.rar
- 导包步骤: 右键project->property->java build path->libaries->add external jars
- 创建实体类
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; } }
- 创建和配置实体类对应的映射文件Product.hbm.xml,推荐将实体和映射文件放到同一个包下,便于管理,文件名 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"> <class name="Product" table="product_"> <id name="id" column="id"> <generator class="native"> </generator> </id> <property name="name" /> <property name="price" /> </class> </hibernate-mapping>
- 创建和配置Hibernate框架的配置文件,在src目录下创建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.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" /> </session-factory> </hibernate-configuration>
- 测试类TestHibernate
public class TestHibernate { public static void main(String[] args) { // 1.获取SessionFactory SessionFactory sf = new Configuration().configure().buildSessionFactory(); // 2.获取一个Session Session s = sf.openSession(); // 3.开启一个事务 s.beginTransaction(); Product p = new Product(); p.setName("iphone7"); p.setPrice(7000); s.save(p); // 4.提交事务 s.getTransaction().commit(); s.close(); sf.close(); } }
通过api对数据库进行增删改查操作
实例类对象在Hibernate中有三种状态:
- 瞬时: 指的是没有和hibernate发生任何关系,在数据库中也没有对应的记录,一旦JVM结束,这个对象也就消失了
- 持久:指得是一个对象和hibernate发生联系,有对应的session,并且在数据库中有对应的一条记录
- 脱管: 指的是一个对象虽然在数据库中有对应的一条记录,但是它所对应的session已经关闭了
通过ID获取一个对象:
还可以通过load方式,两者的区别是:
- load方法是延迟加载,只有属性被访问的时候才会调用sql语句。如果对象不存在抛出异常。
- get方法是非延迟加载,无论后面的代买是否会被访问到属性,马上执行sql语句。如果对象不存在返回null。
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); // 获取一个对象,ID为6 System.out.println("id=6的产品名称是: "+p.getName()); s.getTransaction().commit(); s.close(); sf.close(); } }
通过获取对象后,删除一个对象: 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); //1.先获取对象
s.delete(p); //2.再删除对象
s.getTransaction().commit();
s.close();
sf.close();
}
}
修改一个对象的属性:
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); //1.先获取对象 System.out.println(p.getName()); p.setName("iphone-modified"); //2.对获取的对象进行修改属性 s.update(p); //3.更新修改后的对象 s.getTransaction().commit(); s.close(); sf.close(); } }
查询对象:
使用HQL,根据name进行模糊查询。(使用hql用的类名Product,而不是表名。不需要在前面加select)
- 首先根据hql创建一个Query对象
- 设置参数(以0为基准,PreparedStatement是以1开始)
- 通过Query对象的list()方法返回查询的结果。
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 查询
- 通过session的createCriteria创建一个Criteria对象
- Criteria.add增加约束。
- 调用list()方法返回查询的结果
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(); } }
- 使用Criteria进行分页查询
- 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(); } }
查询总数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(); } }
使用标准的sql查询:
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(); } }
Hibernate之间的实体关系:
多对一
- 除了product产品类,再加一个Category种类的实体(其实体类和映射文件Category.hbm.xml)类似于Product类。一个产品对应一个种类,一个种类对应多个产品
- 在Product类中增加Category属性,在Product.hbm.xml对应的映射文件中
<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" /> </class> </hibernate-mapping>
- 在hibernate.cfg.xml中增加Category的映射<mapping resource="com/how2java/pojo/Category.hbm.xml" />
- 通过代码测试:
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(); } }
一对多
- 为Category类增加一个Set集合
- 为Category.hbm.xml增加one-to-many映射
<set name="products" lazy="false"> <key column="cid" not-null="false" /> <one-to-many class="Product" /> </set>
- 测试
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(); } }
多对多
用户和产品之间的关系。
- 增加User.java实体类
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 实体类
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关系
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(); } }
级联:如果配置了级联,删除分类的时候,对应的产品也都会被删除掉。
- all:所有操作都执行的级联操作
- none:所有操作都不执行级联操作
- delete:删除时执行级联操作
- save-update:保存和更新时执行级联操作
级联通常在one-to-many和many-to-many上,几乎不用在many-one上。
例如:
- 在一对多的基础上,修改test类中
Category c = (Category) s.get(Category.class, 3); s.delete(c); //删除一的一方
- 在对应的Category.hbm.xml中 cascade
<set name="products" cascade="delete" lazy="false">
运行代码就会发现,删除分类的时候,会把分类下对应的产品都删除掉,否则只会把产品对应的cid设置为空
一级缓存:
hibernate默认是开启一级缓存的,一级缓存存放在session上。
- 第一次通过id=1获取对象的时候,session中是没有对应缓存对象的,所以会在"log1"后出现sql查询语句。
- 第二次通过id=1获取对象的时候,session中有对应的缓存对象,所以在"log2"后不会出现sql查询语句
二级缓存:
二级缓存是在SessionFactory上,创建了两个Session
在第一个Session里
- 第一次获取id=1的Category 会执行SQL语句
- 第二次获取id=1的Category,不会执行SQL语句,因为有一级缓存
- 获取id=1的Category,会执行SQL语句,因为在第二个Session,没有缓存该对象。
- 所以总共会看到两条SQL语句。
- 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=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>在src目录下,创建一个ehcache.xml用于EHCache的缓存配置
<ehcache> <diskStore path="java.io.tmpdir"/> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" /> </ehcache>对于要进行二级缓存的实体类映射文件进行配置。
<?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有两种获取session的方式:
openSession和getCurrentSession
1. 获取的是否是同一个session对象
openSession每次都会得到一个新的Session对象getCurrentSession在同一个线程中,每次都是获取相同的Session对象,但是在不同的线程中获取的是不同的Session对象
2. 事务提交的必要性
openSession只有在增加,删除,修改的时候需要事务,查询时不需要的getCurrentSession是所有操作都必须放在事务中进行,并且提交事务后,session就自动关闭,不能够再进行关闭
Hibernate N+1:
Hibernate有缓存机制,可以通过用id作为key把product对象保存在缓存中
同时hibernate也提供Query的查询方式。假设数据库中有100条记录,其中有30条记录在缓存中,但是使用Query的list方法,就会所有的100条数据都从数据库中查询,而无视这30条缓存中的记录 。
同时hibernate也提供Query的查询方式。假设数据库中有100条记录,其中有30条记录在缓存中,但是使用Query的list方法,就会所有的100条数据都从数据库中查询,而无视这30条缓存中的记录 。
而N+1,首先执行一条sql语句,去查询这100条记录,但是,只返回这100条记录的ID然后再根据id,进行进一步查询。
如果id在缓存中,就从缓存中获取,否则再取数据库。
N+1中的1,就是指只返回id的SQL语句,N指的是如果在缓存中找不到对应的数据,就到数据库中去查
Hibernate使用乐观锁处理脏数据问题:
1. 通过session1得到id=1的对象 product1
2. 在product1原来价格的基础上增加1000
3. 更新product1之前,通过session2得到id=1的对象product2
4. 在product2原来价格的基础上增加1000
5. 更新product1
6. 更新product2
2. 在product1原来价格的基础上增加1000
3. 更新product1之前,通过session2得到id=1的对象product2
4. 在product2原来价格的基础上增加1000
5. 更新product1
6. 更新product2
结果只增加了1000
修改配置文件 Product.hbm.xml 增加一个version字段,用于版本信息控制。这就是乐观锁的核心机制。
比如session1获取product1的时候,version=1。 那么session1更新product1的时候,就需要确保version还是1才可以进行更新,并且更新结束后,把version改为2。
比如session1获取product1的时候,version=1。 那么session1更新product1的时候,就需要确保version还是1才可以进行更新,并且更新结束后,把version改为2。
<?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实体类,增加int version作为属性
数据库连接池:
建立数据库连接时比较消耗时间的,所以通常都会采用数据库连接池的技术来建立多条数据库连接,并且在将来持续使用,从而节约掉建立数据库连接的时间
hibernate本身是提供了数据库连接池的,但是hibernate官网也不推荐使用他自带的数据库连接池。
一般都会使用第三方的数据库连接池
C3P0是免费的第三方的数据库连接池,并且有不错的表现
右边可以下载c3p0的jar包 , 只有在高并发量的情况下,才会体会数据库连接池的优越。
hibernate本身是提供了数据库连接池的,但是hibernate官网也不推荐使用他自带的数据库连接池。
一般都会使用第三方的数据库连接池
C3P0是免费的第三方的数据库连接池,并且有不错的表现
右边可以下载c3p0的jar包 , 只有在高并发量的情况下,才会体会数据库连接池的优越。
- 下载导入c3p0jar包
- 进行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>
- 去掉实体类映射文件中的二级缓存<cache usage="read-only" />
- 测试类
public class TestHibernate { public static void main(String[] args) { SessionFactory sf = new Configuration().configure().buildSessionFactory(); Session s = sf.openSession(); s.beginTransaction(); s.createQuery("from Category").list(); s.getTransaction().commit(); s.close(); sf.close(); } }
Hibernate注解:
本来放在hbm.xml文件里的映射信息,现在不用配置文件做了,改由注解来完成
使用注解的实体类
@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 配置文件改动
将<mapping resource="com/how2java/pojo/Product.hbm.xml" />注释掉
增加<mapping class="com.how2java.pojo.Product" />
注解的相关解释:
类注解
- @Entity 表示这是一个实体类,用于映射表
- @Table(name = "product_") 表示这是一个类,映射到的表名:product_
@Entity @Table(name = "product_") public class Product { int id; String name; float price; }
属性注解
- @Id 表示这是主键
- @GeneratedValue(strategy = GenerationType.IDENTITY) 表示自增长方式使用mysql自带的
- @Column(name = "id") 表示映射到字段id
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") public int getId() { return id; }
@Column(name = "price")public float getPrice() {return price;}
多对一注解
@ManyToOne 表示多对一关系
@JoinColumn(name="cid") 表示关系字段是cid
一对多注解
@OneToMany(fetch=FetchType.EAGER) fetch=FetchType.EAGER 表示不进行延迟加载(FetchType.LAZY表示要进行延迟加载)
@JoinColumn(name="cid")
多对多注解
ManyToMany
为Product的getUsers加上
对比Product.hbm.xml中的配置:
为User的getProducts加上
对比User.hbm.xml中的配置
6. hibernate.cfg.xml
@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>
<mapping class="com.how2java.pojo.Product" />
<mapping class="com.how2java.pojo.Category" />
<mapping class="com.how2java.pojo.User" />