12月9日——培训第17天

上午课程开始:

回顾:配置文件和映射文件;SessionFactory和Session的使用注意事项

配置文件
1 使用XML :
调用Configuration.configure()方法,如果不传入参数的话,必须用默认名称hibernate.cfg.xml
传入参数的话就可以用别的名称了

2 使用properties文件:
文件名只能是hibernate.properties,放在工程目录下,不用调用configure()方法,如果调用了的话,
xml配置信息将会覆盖属性文件中配置好的信息。

映射文件
1 直接在hibernate.cfg.xml中,以mapping元素形式加入映射文件(如果用的是属性文件的话就没戏了)
2 addClass,addFile,addResource方法导入映射文件,注意如果使用addClass的话,导入的是与类同名的、
  并以hbm.xml结尾的文件。

--------------------
使用SessionFactory和Session:

整个程序中只能有一个SessionFactory实例,每个线程中只能有一个Session(使用TreadLocal)
SessionFactory里面有许多的Map,每个Map都存了许多的东西,占用内存较大

注意Hibernate3中SessionFactory提供了一个getCurrentSession方法避免了线程间session的冲突问题。
也就是执行语句:session=factory.getCurrentSession();

注意要想执行上述语句的话必须首先在配置文件中的session-factory元素中加入:
<property name="current_session_context_class">thread</property> 
或者在属性文件中加入:hibernate.current_session_context_class thread
也是可以的。
---------------------
1 知道如何在不使用默认文件名时,也能配置Hibernate。知道SessionFactory和Session在编程的时候需要注意什么问题?
2 对象的三种状态分别是什么?含义?
3 update方法和merge方法的区别,应用场合?
4 saveOrUpdate方法应用场合?
5 主键生成器什么意思?为什么实体一定要有标识符?如果数据表中没有主键的话,能否映射对象???
6 HQL,Hibernate Query Language 要求必须非常熟练的掌握。

-----------------------------
一次会话状态中,持久化对象经历以下三种状态:
1 transient:对象不与数据库中任意数据相关联。(也就是主键上面没有值)
2 persistent:对象与数据库中的数据关联,包含持久标识,Hibernate保证对象持久标识与数据库主键一致。
3 detached(脱管、游离状态)

session = factory.getCurrentSession();
session.beginTransaction();
User u = new User();//u相对于session没有发生过任何关系,是临时状态的
u.setId(3);        //现在u设置了主键,因此是脱管状态的(transient)

session.save(u);  //将与事件关联的对象缓存到与当前Session相对应的PersistenceContext对象中,
      //Session.flush()会生成一个flush()事件,从而写数据库。
      //save(u)也就是让u缓存到session中成为一个持久状态
u.setUsername("a");
session.getTransaction().commit();
u.setPassword("bb");  //事务一旦commit,u已经不存在于session的缓存里面,这样再对u进行的操作就不会影响数据库了
      //这时u是脱管或是游离状态。所谓脱管就是和数据库没有关系了。
      //想让它再和session发生关系的话,就再创建一个session
注意:如果使用的是getCurrentSession来创建session的话,在commit后,session就自动被关闭了,
也就是不用再session.close()了。
但是如果使用的是openSession方法创建的session的话,那么必须显示的关闭session,也就是
调用session.close()方法。这样commit后,session并没有关闭,对象还是持久状态,而非脱管状态。
除非调用了session.close(),才是脱管状态。

session = factory.getCurrentSession();
session.beginTransaction();
session.saveOrUpdate(u);
session.getTransaction().commit();

//不论是脱管状态还是临时状态,save一定作插入,update则一定作更新!
//使用saveOrUpdate方法的话,如果对象处于临时状态的话会进行插入,如果是脱管状态的话会更新。

//如果我把一个脱管的对象u.setId(0)的话,由于id是主键,是整型,那么被置为0后就会被认为没有主键了,
//既然没有了主键那就是临时状态,而不再是脱管状态了

//就是说,如果对象里面的整型主键是0的话,且和session没有关系,那么就是临时状态,如果是非0值的话,
//就是脱管状态!

//在映射文件中的id元素中有一个属性叫做unsaved-value="",如果设置了是整数5的话,那么主键设置为5
//会被默认为没有主键,调用saveOrUpdate方法的话肯定是去插入而不是去更新

saveOrUpdate执行的伪代码:
if(obj.getId()==unsavedValue)
{
 save(obj);
}
else
{
 update(obj);
}

 

session的save,persist,load,update,get等方法都是把临时状态转换为一个持久状态,将对象
和session相关联。

注意:在持久状态中,对对象的任何操作都会先写缓存,在commit后这些操作会反映到数据库。

save无论对象是否处于临时状态都会向数据库中保存的,但是persisit只会去持久化那些处于临时状态中
的对象(那些没有主键的对象,也就是被设置成unsaved-value值主键的对象)

临时状态的最大特点是主键值与unsaved-value值相同!!
------------------------------------------
代码片断1:

//临时状态
   //最大特点是ID与unsaved-value的值相同。
   User u = new User();
   
   
   session = factory.openSession();
   session.beginTransaction();
   
   //持久状态
   /*
    * 因为u的ID值为0,而在映射文件中没有指定unsaved-value值,所以默认为0
    * 程序在执行saveOrUpdate时,会判断ID值是否与unsaved-value相同,如果
    * 相同则执行save
    */
   session.saveOrUpdate(u);
   u.setUsername("a");
   
   session.getTransaction().commit();

  注意:session.saveOrUpdate(u)这条语句://如果执行的是save则立刻执行,如果是update则到flush时才执行
 还有一点,session.save(Object)方法返回的值是主键的值!
----------------------------------------
session.beginTransaction();
session.get(User.class,new Integer(u.getId()));
session.update(u); //注意上面那句话已经让session中缓存了对象u,如果再次进行update的操作的话
     //会出现错误!!如果不想错误发生的话,应该把update方法改为merge来进行更新!
session.getTransaction.commit();

----------------------------------------
代码片断2:
//临时状态
   //最大特点是ID与unsaved-value的值相同。
   User u = new User();
   
   session = factory.openSession();
   session.beginTransaction();
   
   //持久状态
   /*
    * 因为u的ID值为5,而在映射文件中没有指定unsaved-value值,所以默认为0
    * 程序在执行saveOrUpdate时,会判断ID值是否与unsaved-value相同,如果
    * 不相同则执行update
    */
   
   session.saveOrUpdate(u);//如果执行的是save则立刻执行,如果是update则到flush时才执行
   
   u.setUsername("a");
   
   session.getTransaction().commit();
   
   //使用session.openSession在事务提交不会关闭session,
   //所以u处于持久状态(只有session关闭之后,u才会变为脱管状态)
   u.setPassword("bb");
   session.beginTransaction();
   session.getTransaction().commit();
   session.close();
   
   //脱管状态(游离)detached
   u.setUsername("cccc");
   
   session = factory.getCurrentSession();
   session.beginTransaction();
   session.get(User.class, new Integer(u.getId()));
   session.update(u); //这里如果不用merge的话是没有办法更新的,但是这里可以用save进行插入
   session.getTransaction().commit();
------------------------------------------------
明天是张老师讲邮件服务器的细节,具体来说是怎么样用程序来实现收发邮件的问题。


下午提前30分钟上课,不知为何……
对象的三种状态分别是什么?含义?
1 临时:没有和session发生关系的,没有主键的(默认情况下整型主键值为0,对象型主键值为null时)。
2 脱管:和临时相比有了主键信息,也就是主键值不等于unsaved-value
3 持久:和session相关对象。

只有session里面没有缓存u时,才可以使用session.update(u)。如果session中有了一个对象和u的主键
已经相同了,就不允许使用session的update方法了

如果不确定这个session缓存里面是否有一个对象和u的主键有相同的值,那么使用merge来覆盖掉原来缓存
中的对象,从而达到更新的目的。

saveOrUpdate方法的应用场合:不确定记录是否要被插入到数据表中。
什么时候执行save呢?
对象主键的id等于unsaved-value的时候执行save。

什么时候执行update呢?
对象主键的id不等于unsaved-value的时候执行update。
--------------------------
再说说ThreadLocal,
教室里面每个人都是一个线程,每个人的杯子都是一个ThreadLocal,前面有一杯水是session,还有一个
水缸是sessionFactory,如果每个人都要取水的话都得在水缸前面排队,这就是线程安全。

这样每一个线程都有了一个session,ThreadLocal是每个人手里的杯子,杯子里面都可以装水(session)。
--------------------------
主键生成器是什么意思??为什么实体一定要有标识符?
没有主键的话还能不能映射对象了?

主键生成器:<generator class="identity"/>
在org.hibernate.id中包含IdentifierGenerator接口。
可以用org.hibernate.id.IdentityGenerator替换上面的identity。

其实identity是简写。

主键是不用插入的,主键生成器是用来把插入记录生成的主键读出来放到对象里面的相应标识中去。
注意:select last_insert_id();如果和插入语句放在同一个事务中,那么可以用它来得到最后一条
插入记录的主键,如果它没有和插入语句放在同一个事务中,那执行起来就没有效果了。
-------------------------------------

下面讲HQL
session = factory.getCurrentSession();//注意如果要想使用这句话的话必须
        //<property name="current_session_context_class">thread</property>
session.beginTransaction();
User u = (User)session.load(User.class,new Integer(3));
//上面这种方式的加载如果不知道主键的话根本没有意义,如果我要想根据某些字段来查询表中的相应
//记录集合的时候,用这种方法来加载是不行的
//弊端:只能通过主键来加载对象,限制了Hibernate的应用

//如果我想根据用户名和密码查询的话,HQL语句应该如何写呢?

//如下所示,语句hql是从类里面找满足条件的对象,注意user是vo.User的别名,vo是类所在的包名。
//如果我不想加入包名的话,那么就得在映射文件的hibernate-mapping元素中设置auto-import属性,
//将之设置为true,就不用引入包了!
String hql = "from vo.User user where user.username=? and user.password=? "
Query q = session.createQuery(hql);  //x需要导入org.Hibernate.Query包
q.setString(0,"j2se");
q.setString(1,"1");  
List l = q.list();    //这句话也需要导入包!
Iterator it = l.iterator();
if(it.hasNext())
{
 System.out.println("找到了!");
}
else
{
 System.out.println("哎,没找到啊!");
}

session.getTransaction().commit();

//上面iterator中存的就是对象!

while(it.hasNext())
{
 System.out.println(it.next().getClass());
 User u = (User)it.next();
}
-----------------------------------------------------------------
使用Hibernate实现用户登陆和修改密码的小例子:


package practice;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Iterator;
import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class Test {
 
 public static String readLine()
 {
  String result = "";
  BufferedReader in = new BufferedReader(
       new InputStreamReader(System.in));
  try {
   result = in.readLine();
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  return result ;
 }
 
 public static void main(String[] args) {
 
  
  System.out.println("请您输入登陆的用户名和密码!");
  System.out.println("×××××××××××××××××××××××××××××××");
  System.out.println("请您输入用户名:");
  String username = Test.readLine();
  System.out.println("请您输入密码:");
  String password = Test.readLine();
  
  
  Entity entity = new Entity();
  
  SessionFactory factory =
   new Configuration().addClass(Entity.class).
    configure().buildSessionFactory();
  Session session = factory.getCurrentSession();
  
  session.beginTransaction();
  
  String hql = "from practice.Entity e where e.name=? and e.password=?";
  
  Query q = session.createQuery(hql);
  q.setString(0,username);
  q.setString(1,password);
  
  List list = q.list();
  Iterator it = list.iterator();
  
  if(it.hasNext())
  {
   System.out.println("您的输入正确!欢迎登陆");
   entity = (Entity)it.next();
  }
  else
  {
   System.out.println("输入的用户名、密码有误,下次小心点!");
   System.exit(1);
  }  
  session.getTransaction().commit();//很重要!在登陆完毕后就关闭session!后面用到的时候再创建!
  
  System.out.println("*************************************");
  System.out.println("请您输入您的新密码:");
  String password1 = Test.readLine();
  System.out.println("请您再次输入您的新密码:");
  String password2 = Test.readLine();
  if(!password1.equals(password2))
  {
   System.out.println("两次输入的密码不一致,下次小心点!");
   System.out.println("***************");
   System.exit(1);
  }
  
  entity.setPassword(password1); //这时候entity对象毫无疑问处于脱管状态!
  
  session = factory.getCurrentSession();
  session.beginTransaction();
  session.update(entity);//注意这里可以用saveOrUpdate和merge方法也可以达到同样的效果!
  System.out.println("密码已经成功的被更新!!!");
  session.getTransaction().commit();

 }
}
---------------------------------
再次注意下面的配置语句:
<hibernate-mapping auto-import="true" package="vo">
这里的auto-import是在hql语句中不用写包名了,那个package则是保证在下面的配置信息中的class的name属性
中不必输入包名了!

//如果不加select的话默认选取出的是整个对象,只有像下面这样写才能够取出具体的属性
Query q = session.createQuery("select username from User where id=1");
String name = (String)q.uniqueResult();
System.out.println(name);
-----------------------------------------

<property name="name" column="name"/>
其实里面还有一个叫做type的属性可以加上数据类型,这样指明了每个字段的数据类型的话运行起来会快一点,
要不程序还得自己去根据反射机制去查找数据类型,挺麻烦的。

mysql中的timestamp对插入操作会相应的把时间置为当前的时间。
但是oracle中的时间戳完全不一样

select systimestamp from dual;
会得到09-12月-06 04.26.46.312000 下午 +08.00 ,也就是说oracle中包含了很详细的时间
甚至有毫秒、时区等信息。

date,time, timestamp,calendar,calendar_date
string , varchar ,
integer,long,short,float,double,byte,character,boolean,true_false,yes_no

以上的这些类型都可以加入到<property name="name" column="name"/>
的type属性中去。

---------------------
总结:

对象三种状态,update和merge区别,saveOrUpdate应用场合,unsaved-value,HQL语句掌握
使用SessionFactory和Session注意的问题,

当然还有一个今天没有太讲清楚的主键生成器!

注意以下每行方法的对比、区别
save、persist、saveOrUpdate
update、merge、saveOrUpdate
load、get
load->setter、update

练习:
使用命令行方式实现用户注册,修改用户注册信息的功能,要求实现Hibernate实现。
考虑性能问题,一定要注意及时的关闭session!

明天是张老师讲JavaMail,后天是Hibernate中hql的qbe和qbc之类的东西,Hibernate进行完后
是javaScript要讲一讲,然后是Javaweb、Struts、Sprint、设计模式、工作流之类的东东。

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

使用命令行方式实现用户注册,修改用户注册信息的功能,要求实现Hibernate实现。
考虑性能问题,一定要注意及时的关闭session!

晚上练习的答案:

配置文件hibernate.cfg.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
 "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
 "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
 
<hibernate-configuration>
  <session-factory>
   <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
   <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
   <property name="connection.url">jdbc:mysql:///j2ee</property>
   <property name="connection.username">root</property>
   <property name="connection.password">root</property>
   
   
   <property name="format_sql">root</property>
   <property name="current_session_context_class">thread</property>
   <property name="show_sql">false</property>
   
   <mapping resource="aw/User.xml"/>
  </session-factory>
 
</hibernate-configuration>
**********************************************

映射文件User.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
 <class name="aw.User" table="users">
  <id name="id">
   <generator class="identity"/>
  </id>
  <property name="name"/>
  <property name="password"/>
  <property name="loginTimes"/>
  <property name="loginTime"/>
 </class>

</hibernate-mapping>
**********************************************

实体类User:

package aw;

import java.sql.Timestamp;

public class User {
 private int loginTimes ;
 private Timestamp loginTime ;
 private String name ;
 private String password ;
 private int id ;
 public int getId() {
  return id;
 }
 public void setId(int id) {
  this.id = id;
 }
 public Timestamp getLoginTime() {
  return loginTime;
 }
 public void setLoginTime(Timestamp loginTime) {
  this.loginTime = loginTime;
 }
 public int getLoginTimes() {
  return loginTimes;
 }
 public void setLoginTimes(int loginTimes) {
  this.loginTimes = loginTimes;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public String getPassword() {
  return password;
 }
 public void setPassword(String password) {
  this.password = password;
 }
 


}
×××××××××××××××××××××××××××××××××××××××××××××××××
源程序:

package aw;
import java.util.Iterator;
import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import java.io.*;
public class Aaa {
 
 //从控制台读一行后返回相应的字符串!
 public static String readLine()
 {
  try {
   return new BufferedReader(new InputStreamReader(System.in)).readLine();
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
   return "";
  }
 }
 
 //判断用户名是否已经存在
 public static boolean existsUser(SessionFactory factory,String username)
 {
  boolean result = false ;
  Session session = factory.getCurrentSession();
  
  session.beginTransaction();
  
  String hql = "from aw.User where name=?";
  Query q = session.createQuery(hql);
  q.setString(0,username);
  List list = q.list();
  Iterator it = list.iterator();
  if(it.hasNext())
   result = true ;
  
  session.getTransaction().commit();
  
  return result ;
  
 }
 
 
 
 
 //进行注册处理
 public static void register(User u, SessionFactory factory)
 {
  boolean flag = false ;
  System.out.println("现在开始注册:请您输入用户名");
  String username= readLine();
  if(existsUser(factory,username))
  {
   System.out.println("真是非常非常的抱歉,该用户名存在了!");
   flag = true ;
   register(u,factory);
  }
  //递规调用后必然要回到这里,如果执行了递规调用的话那么下面的代码没有执行
  //的意义,所以要根据flag的值决定是否返回入口点。
  if(flag==true)
   return ; //这句话非常的重要!不可丢失
  //下面是正常的注册逻辑!
  System.out.println("用户名输入成功,您再输入一下密码吧:");
  String password = readLine();
  //下面开始插入数据库!!
  
  u.setName(username);
  u.setPassword(password);
  Session session = factory.getCurrentSession();
  session.beginTransaction();
   session.save(u);
  
  System.out.println("您的注册已经完成了!");
  session.getTransaction().commit();
  return;
 }
 
 //修改密码处理:
 public static void modify(User u, SessionFactory factory)
 {
  System.out.println("请您输入新密码");
  String password = readLine();
  
  u.setPassword(password);
  Session session = factory.getCurrentSession();
  session.beginTransaction();
   session.update(u);
   System.out.println("密码修改完毕!!");
  session.getTransaction().commit();
 }
 
 public static void main(String[] args)
 {
  SessionFactory factory = new Configuration().configure()
        .buildSessionFactory();
  User u = new User();
  System.out.println("*****************************");
  register(u,factory);
  System.out.println("*****************************");
  System.out.println("请您输入新的密码:");
  
  modify(u,factory);
 }
}

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值