关于hibernate操作

来源:互联网 发布:天小猫淘宝信誉查询 编辑:程序博客网 时间:2024/06/15 00:00

一、load与get方法的区别:

首先观察这样一个实验
Student stu=(Student) session.get(Student.class, 1); //切换这个位置
System.out.println("--------------------------------我是华丽丽的风格线----------------------------------------------------");
System.out.println(stu.getStuName());


当使用load方法来得到一个对象时,此时hibernate会使用延迟加载的机制来加载这个对象,即:当我们使用session.load()方法来加载一个对象时,此时并不会发出sql语句,当前得到的这个对象其实是一个代理对象,这个代理对象只保存了实体对象的id值,只有当我们要使用这个对象,得到其它属性时,这个时候才会发出sql语句,从数据库中去查询我们的对象。


相对于load的延迟加载方式,get就直接的多,当我们使用session.get()方法来得到一个对象时,不管我们使不使用这个对象,此时都会发出sql语句去从数据库中查询出来:


因此我们可以看到,使用load的加载方式比get的加载方式性能要好一些,因为load加载时,得到的只是一个代理对象,当真正需要使用这个对象时再去从数据库中查询。


如果使用get方式来加载对象,当我们试图得到一个id不存在的对象时,此时会报NullPointException的异常



如果使用load方式来加载对象,当我们试图得到一个id不存在的对象时,此时会报ObjectNotFoundException异常:


get查询为空会得到一个null而load会报异常



(1)get()方法直接返回实体类,如果查不到数据则返回null。load()会返回一个实体代理对象(当前这个对象可以自动转化为实体对象),但当代理对象被调用时,如果没有数据不存在,就会抛出个org.hibernate.ObjectNotFoundException异常


(2)load先到缓存(session缓存 一级缓存/二级缓存)中去查,如果没有则返回一个代理对象(不马上到DB中去找),等后面使用这个代理对象操作的时候,才到DB中查询,这就是我们常说的 load在默认情况下支持延迟加载(lazy)
load--seesion/二级缓存 ---数据库执行
 


(3) get先到缓存(session缓存/二级缓存)中去查,如果没有就到DB中去查(即马上发出sql)。总之,如果你确定DB中有这个对象就用load(),不确定就用get()(这样效率高)


(4)get和load查询数据库


1. 如果查询不到数据,get 会返回 null,但是不会报错, load 如果查询不到数据,则报错ObjectNotFoundException


2. 使用get 去查询数据,(先到一级/二级)会立即向db发出查询请求(select ...), 如果你使用的是 load查询数据,(先到一级、二级))即使查询到对象,返回的是一个代理对象,如果后面没有使用查询结果,它不会真的向数据库发select ,当程序员使用查询结果的时候才真的发出select ,这个现象我们称为懒加载(lazy)


3. 通过修改配置文件(*.hbm.xml文件),我们可以取消懒加载



Query query=session.createQuery("from User u where u.userName=?");
query.setString(0, "test");
Iterator<User> it=query.list().iterator();
while(it.hasNext()){
User u=it.next();
System.out.println(u.getUserName());
}
-------------------------------------------------------------------------------------------------------------------------------------------


二、 many-to-one

使用表为emp和dept
配置文件中配置
<many-to-one name="dept" class="com.wode.entity.Dept" column="deptNo" />


将两个表关联起来

完成案例增加和查找


注意在我们使用get的时候,当我们正真去使用连接表数据的时候,才会发出sql语句,这是因为hibernate自动使用了延迟加载。
可以在配置文件中修改
<many-to-one name="dept" class="com.wode.entity.Dept" column="deptNo" lazy="false"/>



我们发现这种方式其实是用了两个sql语句进行了查找。我们也可以使用一条sal语句来做这个事情。
many-to-one name="dept" class="com.wode.entity.Dept" column="deptNo" lazy="false" fetch="join"/>


Emp emp=(Emp) session.get(Emp.class, 5);
System.out.println(emp.getDept().getDeptNo());
这里要注意的时候,这种做法只对get方法有作用,如果用HQL就没有用了
List<Emp> list=session.createQuery("from Emp").list();
System.out.println(list.get(0).getDept().getDeptNo());
System.out.println(list.get(1).getDept().getDeptNo());


如果必须要在HQL中使用呢?
List<Emp> list=session.createQuery("from Emp e left join fetch e.dept").list();
System.out.println(list.get(0).getDept().getDeptNo());
System.out.println(list.get(1).getDept().getDeptNo());


使用参数根据ID查询用户
Query query=session.createQuery("from Emp e where e.empno=?");
query.setParameter(0, 7654);
List<Emp> list=query.list();
for(Emp emp:list){
System.out.println(emp.getEname());
System.out.println(emp.getDept().getDname());
}


案例1:新增
Order order=new Order();
order.setCreateDate(new Date());

Item item=new Item();
item.setProductName("iphone");
item.setPrice(new BigDecimal("90.90"));
item.setAmount(2);
item.setOrder(order);

Item item2=new Item();
item2.setProductName("ipad");
item2.setPrice(new BigDecimal("190.90"));
item2.setAmount(1);
item.setOrder(order);
order.getItems().add(item);
order.getItems().add(item2);
session.save(order);
Transaction tx=session.beginTransaction();
tx.commit();


我们发现报错了?为什么呢?
<set name="items" cascade="all">我们需要这样配置
级联操作all 代表所有的。当然我们如果只是增加和修改的话可以配置为save-update


删除订单。
Order order=new Order();
order.setId(8);
session.delete(order);
Transaction transaction=session.beginTransaction();
transaction.commit();
发现这样错误。在hibernate中必须先去查一次再删除。
修改
// Order order=new Order();
// order.setId(8);
// session.delete(order);
Order order=(Order) session.get(Order.class, 8);
session.delete(order);
Transaction transaction=session.beginTransaction();
transaction.commit();


这样就可以了。但是必须要注意的是cascade="all"级联操作必须这样做,当然如果只为删除的话就可以写成cascade="delete"




实验:删除order中的某一个item
Order order=(Order) session.get(Order.class, 11);
Set<Item> items=order.getItems();
System.out.println(items.size());
Iterator<Item> it=items.iterator();
while(it.hasNext()){
if(it.next().getProductName().equals("ipad")){
it.remove();
}
}
System.out.println(items.size());
Transaction transaction=session.beginTransaction();
transaction.commit();


实验成功,但是数据库的数据没有发生改变。


关键是级联
我们修改 <set name="items" cascade="all-delete-orphan" inverse="true">这样就可以了,那想想cascade的值有哪些呢?


实验:通过get获取order这时候发现, lazy="false"设置延迟加载关闭,发现多次请求
同样的这里可以这样设置fetch="join"



实验,查找所有的订单以及所有订单里面的条目
@Test
public void findAll(){
List<Order> orders=session.createQuery("from Order").list();
for(Order order:orders){
System.out.println(order.getCreateDate()+" "+order.getId());
for(Item item:order.getItems()){
System.out.println(item.getProductName()+" "+item.getPrice());
}
}
}


去重,并且sql语句不会重复执行,直接链表查询
List<Order> orders=session.createQuery("select distinct o from Order o join fetch o.id").list();


-----------------------------------------------------------------------------------------------------------------------------------------------------------------

三、多对多关系


student--选多门课程course
课程course--被多个学生选择


需要建立中间表;


在配置文件中
  <set name="courses" table="t_s_fk">
        <key column="sId"></key>
        <many-to-many class="Course" column="cId"></many-to-many>
        </set>
案例,新增学生和课程。
案例,让学生选择自己要学的课程。
Student student=(Student) session.get(Student.class, 4);
Course course=(Course) session.get(Course.class, 1);
Course course2=(Course) session.get(Course.class, 2);
student.getCourses().add(course);
student.getCourses().add(course2);
Transaction tx=session.beginTransaction();
tx.commit();




案例2:通过科目名称查找选了这门课程的学生
Query query=session.createQuery("from Student s  join " +
" fetch s.courses c where c.courseName=?");
query.setParameter(0, "html");
List<Student> students=query.list();
for(Student student:students){
System.out.println(student.getStuName());
}

-----------------------------------------------------------------------------------------------------------------------------------------------

hibernate提供了非常方便的分页方法,当然是要使用Query这个东西了
Query query=session.createQuery("from Course");
//当前页数
int currPage=1;
//一页显示数据
int rowPage=3;
query.setFirstResult((currPage-1)*rowPage);
query.setMaxResults(rowPage);
List<Course> courses=query.list();
for(Course course:courses){
System.out.println(course.getCourseName());
}


当然query还有更加强大的用法
例如:
Query query=session.createQuery("select count(*) from Course");  hql
Query query=session.createQuery("select courseId from Course");
Query query=session.createQuery("select courseName from Course"); 


我们一直在使用query做增删改查,但是如果我们不用session的方式执行update或者delte怎么办呢》?
Query query=session.createQuery("delete  Course c where  " +
"c.courseName = ‘wa’ ");
int =query.executeUpdate();
 修改操作
这里特别注意的是模糊查询产生的问题


Query query=session.createQuery("delete  Course c where  " +
"c.courseName like :name ");//这样做才可以
query.setParameter("name","%"+"wq"+"%");
query.executeUpdate();

----------------------------------------------------------------------------------------------------------------------------------------

四、hibernate实体类注解


@Entity
@Table(name="users")

@Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
public class User implements Serializable{


@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="user_id")
private int userId;


@Column(name="user_name")
private String userName;


@Column(name="user_pwd")
private String userPwd;


@Column(name="user_type")
private int userType;

}


----------------------------------------------------------------------------------------------------------------------------------

五、在applicationContext中配置

<!-- 配置C3P0数据源   好用   数据库链接 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/school?characterEncoding=utf-8" />
<property name="user" value="root" />
<property name="password" value="root" />
<property name="minPoolSize" value="1" />
<property name="maxPoolSize" value="20" />
<property name="maxIdleTime" value="60" />
<property name="initialPoolSize" value="1" />
<!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 -->
<property name="acquireIncrement" value="5" />
<property name="automaticTestTable" value="c3p0TestTable" />
<!--每60秒检查所有连接池中的空闲连接。Default: 0 -->
<property name="idleConnectionTestPeriod" value="60" />
<property name="checkoutTimeout" value="3000" />
</bean>

<!-- 配置SessionFactory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<!-- 向SessionFactory中注入数据源 -->
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<props>
<!-- 定义Hibernate的方言 -->
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<!-- 是否根据需要每次自动更新数据库 <prop key="hibernate.hbm2ddl.auto">update</prop> -->
<!-- 控制台显示SQL语句 -->
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<!-- 使用SQL注释 -->
<prop key="hibernate.use_sql_comments">true</prop>
<!-- 启用二级缓存 -->
<prop key="cache.use_second_level_cache">true</prop>
<prop key="cache.use_query_cache">true</prop>
<prop key="hibernate.cache.region.factory_class">
org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>
</props>
</property>


<!-- 浏览entity包下的所有使用Hibernate注解的JavaBean -->
<property name="packagesToScan">
<list>
<value>com.wode.entity</value>
</list>
</property>
</bean>

<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>

-----------------------------------------------------------------------------------------------------------------------------------------------------

六、在web.xml中配置

<filter>
    <filter-name>hibernateFilter</filter-name>
    <filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
    <init-param>
      <param-name>sessionFactoryBeanName</param-name>
      <param-value>sessionFactory</param-value>
    </init-param>
    <init-param>
      <param-name>singleSession</param-name>
      <param-value>true</param-value>
    </init-param>
    <init-param>
      <param-name>flushMode</param-name>
      <param-value>AUTO</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>hibernateFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>


这样配置后同一个用户从始至终值获得一个session




原创粉丝点击