12月8日——培训第16天

来源:互联网 发布:rar在linux下解压 编辑:程序博客网 时间:2024/05/13 07:09

昨天晚上借着喝酒交心的功夫,同寝室的宁艳超和兰献斌和田老师好好的作了一番交流,聊了很长时间,提到
上课时间不要安排的过于紧密,要留有一定的练习时间等等。于是今天上午田老师安排我们练习昨天的Hibernate
连接数据库取数据的方法。

好好试了试,还是明白了一些东西的,附上我的源代码如下:

数据库:mysql
建立的库:j2ee
数据表users

字段:
id :主键,默认自增,整型
name:varchar型,不能为空
password:varchar型,不能为空
loginTimes:int型,不能为空
loginTime:Timestamp型(最好设置为Datetime型比较好),不为空

当然了,还是得先导入包,lib文件夹下的所有jar包,还有那个mysql的驱动。
配置文件如下:

1. hibernate.cfg.xml:
------------------------------------
<?xml version="1.0"?>

<!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="show_sql">true</property> 注意这条语句是表示每和数据库交互一次就必须显示sql语句!
  <property name="format_sql">true</property>这条语句是表示要让sql语句按照比较好看的格式来显示出来
 </session-factory>
</hibernate-configuration>
---------------------------------------------------------------------------

2. Entity.hbm.xml
---------------------------------------------------------
<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping> 注意包名是practice,实体类名是Entity,对应表名是users,下面的两个参数可以自己根据情况设置!
 <class name="practice.Entity" table="users" dynamic-update="true" dynamic-insert="false">
  <id name="id" column="id">
   <generator class="identity"/>
  </id>
  
  <property name="name" column="name"/>
  <property name="password" column="password"/>
  <property name="loginTimes" column="loginTimes"/>
  <property name="loginTime" column="loginTime"/>
 </class>
</hibernate-mapping>
--------------------------------------------------------------------------
我自己建立的一个实体类Entity:
package practice;

import java.sql.Timestamp;

public class Entity {
 private int id ;
 private String name ;
 private String password ;
 private int loginTimes ;
 private Timestamp loginTime ;
 private Integer test ;
 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;
 }
 
 public static void main(String[] args)
 {
  Entity e = new Entity();
  System.out.println(e.getLoginTimes());
  System.out.println(e.getLoginTime());
  
 }
 
 public Integer getTest() {
  return test;
 }
 public void setTest(Integer test) {
  this.test = test;
 }
 
}

-------------------------------------
我写的测试类Test:

package practice;

import java.sql.Timestamp;

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

public class Test {

 /**
  * @param args
  */
 public static void main(String[] args) {
  // TODO Auto-generated method stub
 
  //下面这两行是用来得到工厂session,用来操作实体类对象的,最后记得要关闭它!
  SessionFactory factory =
   new Configuration().addClass(Entity.class).configure().buildSessionFactory();
  Session session = factory.openSession();
  
  //插入
  /*Entity e = new Entity();
  //e.setLoginTime(new Timestamp(System.currentTimeMillis()));
  e.setLoginTimes(2);
  e.setName("yyy");
  e.setPassword("yyy");
  
  session.beginTransaction();
  
  session.save(e);
  
  session.getTransaction().commit();  */
  

  
  //选取(当然还有一种选取是不用load,而是用get,load延迟选取,get不延迟)
  /*Entity e = (Entity)session.load(Entity.class,new Integer(1));
  System.out.println(e.getName());
  */
  
  //第一种更新
  session.beginTransaction();
  Entity e = (Entity)session.load(Entity.class,new Integer(5));
  e.setName("43112");
  
  session.getTransaction().commit();
  
  
  //删除
  /*session.beginTransaction();
  Entity e = (Entity)session.load(Entity.class,new Integer(7));
  session.delete(e);
  session.getTransaction().commit();*/
  
  //persist插入:
  /*session.beginTransaction();
  Entity e = new Entity();
  
  e.setName("newyuan");
  e.setPassword("newyuan");
  //e.setLoginTime(new Timestamp(System.currentTimeMillis()));
  session.persist(e);
  session.getTransaction().commit();*/
  
  
  
  //第二种更新:
  /*session.beginTransaction();
  Entity e = new Entity();
  e.setId(5);
  e.setName("123456");
  e.setPassword("123456");
  e.setLoginTimes(2);
  session.update(e);
  session.getTransaction().commit();*/
  
  session.close();
  
  
 }

}
------------------------------------------------------

中午把就业协议发了下来,下午课程开始:

先是走一遍流程:新建工程,导入lib包、mysql驱动,新建一个和数据库中的表对应的类User,
新建配置文件,选other,找MyEclipse中的XML中的dtd选项,选择create xml from dtd
来建立hibernate.cfg.xml。

1 在session-factory中加入多行property元素,
<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> ……………………
还有u用户名和密码

注意还要设置show_sql和format_sql属性。

一般我们现在配置的文件都是以DriverManager的方式来连接的,以后会改为DataSource方式连接!

2 新建User.hbm.xml映射文件,可以在hibernate-mapping中加入package属性,这样底下的class的table中
就不用引入包名了!

而且如果name和column同名的话只写一个name就可以了。

3 然后是自己写一个Demo类来测试Hibernate元素

注意:可以在session-factory的后面加上:<mapping resource="包名/User.hbm.xml"/> 这样就不用建立配置Configuration
时加载class了,但是这样可能会出现内存浪费的情况,可能会加载了许多不需要使用的类!

SessionFactory factory = new Configuration().configure().buildSessionFactory();

Session session = factory.openSession() ;
User u = new User();
u.setUsername("aaa");

session.beginTransaction();
sessin.save(u)
session.getTransaction().commit();

注意:如果发生异常的话,可以在catch中写上session.getTransaction().rollback();
在finally中要记得关闭session,使用session.close();

-----------------------------------
-----------------------------------
今天要掌握的知识点:
对象三种状态以及主键:
1 知道如何在不使用默认文件名时,也能配置Hibernate。知道SessionFactory和Session在编程的时候需要注意什么问题?
2 对象的三种状态分别是什么?含义?
3 update方法和merge方法的区别,应用场合?
4 saveOrUpdate方法应用场合?
5 主键生成器什么意思?为什么实体一定要有标识符?如果数据表中没有主键的话,能否映射对象???
------------------------------------
不使用默认名来配置Hibernate:
一 配置文件Hibernate.cfg.xml:

1 SessionFactory factory = new Configuration().addClass(User.class).
      configure("hibernate.xml").buildSessionFactory();
注意:hibernate.xml就是我自己写的configure配置文件

2 而且我还可以不configure("hibernate.xml")直接去buildSessionFactory();
也就是:
SessionFactory factory = new Configuration().addClass(User.class).
      buildSessionFactory();
但是这时候记得要把hibernate.property属性文件导入类根目录中,去掉其中的相关注释,比如mysql
这时候引入了property文件的话就不用那个xmlconfiguration配置文件了,使用property文件的话
确实也就不用调用那个configure()方法了

3 当property文件和xml配置文件同时使用的话,以xml配置文件为优先

4 再次注意一点:构造会话工厂SessionFactory时,可以不使用添加类的语句,也就是那个
addClass(User.class), 执行到这句话的时候,会去读取那个映射文件,如果在配置文件
中的session-factory元素中加入了<mapping resource="包名/User.hbm.xml"/> 的话,
这样就不用那个addClass方法了!但是不可以同时使用mapping resource标签和addClass方法!!!!

满江红网站上有个叫曹晓钢的人组织了很多人一起翻译Hibernate和Spring的官方文档

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

假设在一个映射文件User.hbm.xml中映射了两个类,那么使用addClass(User.class)就可以
它会直接去找类路径中和User同名的那个User.hbm.xml文件,由于该映射文件中已经有了两个
类映射到了不同的两个表,所以找一个User的映射文件就可以了,所以只需要add一个User.class
就可以了……

或者你在配置文件中去用<mapping resource="包名/User.hbm.xml"/>也是可以的。

注意:addClass还可以替换为addResource("包名/User.hbm.xml")!!!这也是可以的,
而且只要使用了addResource方法的话,映射文件可以任意命名!!

之所以以前一直用 实体类名.hbm.xml是因为使用的是addClass方法,而不是addResource,
要使用addClass必须得用默认的命名!

-------------------------------------
对配置文件和映射文件配置方法的小总结

一 配置文件
1.使用XML文件:(1)默认情况下,Hibernate会到类路径的根路径下(工程文件夹下)去找hibernate.cfg.xml文件,
   这时候调用Configuration.configure()方法时,不需要传入任何参数
   (2)如果使用了其他路径或其他文件名的话,在调用configure时要传入参数,参数类型可以是Document,
   File或者是String类型。

2.使用property属性文件:文件名只能是hibernate.properties,而且在创建Configuration的时候
     不用再调用configure方法,可以直接去调用buildSessionFactory。如果调用了
     configure()方法的话,那么XML配置信息将会覆盖原来已经有的属性文件信息。


二 映射文件:
1 静态:直接在Hibernate.cfg.xml文件中,以mapping元素的形式加入映射文件,属性是resource,例如:
  <mapping resource="包名/user.xml"/>    这里user.xml是映射文件 
或者:<mapping file="f:/cfg/user.xml"/>
resource是往类路径中去找,file是去找本地的文件(要用完整的绝对路径!!)

2 动态:
(1)addClass方法:在类所在的包中去找与类同名的,并且以hbm.xml结尾的文件(不能任意命名映射文件)
(2)addFile方法:文件系统路径(可以任意命名映射文件)
(3)addResource方法:类路径(可以任意命名映射文件)

------------------------------------------------
SessionFactory和session使用时要注意的问题:
一个hibernate.cfg.xml文件与一个SessionFactory相对应,SessionFactory是重量级的,
一个应用程序中只创建一个SessionFactory就可以了,使用单例模式做到这一点。
单例模式也就是让那个类的构造方法私有,然后类的内部返回一个对象就可以,同时,把对象声明为私有静态的final常量对象!
这样整个应用程序中就只有一个对象了!

但是SessionFactory是公共的构造方法,SessionFactory用的不是单例模式,是使用了一个HibernateUtil辅助类,
是为了确保SessionFactory在整个应用程序中只有一个实例!

private static final SessionFactory sessionFactory;
static
{
 try
 {
  sessionFactory = new Configuration.configure().buildSessionFactory();
 }
 catch(HibernateException ex)
 {
  throw new RuntimeException(ex.getMessage(),ex);
 }
 
 
}

Session对象是非线程安全的,要保证一个线程只创建一个session
非线程安全:两个线程同时用一个session修改一个资源的话会造成冲突!!要保证一个线程里面只创建一个Session的话,
public static final ThreadLocal session = new ThreadLocal(); //ThreadLocal是线程本地变量
public static Session currentSession() throws HibernateException
{
 Session s = (Session)thread.get();
 if(s==null)
 {
  s = sessionFactory.openSession();
  thread.set(s);  //如果线程本地变量中没有Session的话,我就创建一个Session,然后把它塞进ThreadLocal中
  //每个线程中都有一块儿ThreadLocal,只有该线程自己才可以访问这块存储空间!其他线程无法访问,该空间用来存储
  //程序员自定义的对象。
 }
 return s ;
}

注意:java的每一个线程中有且仅有一个ThreadLocal,每个ThreadLocal里面仅仅能存放一个对象!!

如果使用HibernateUtil.currentSession的话,必须使用HibernateUtil.closeSession,
而不能使用session.close();

HibernateUtil类的closeSession方法:
public static void closeSession() throws HibernateException
{
 Session s = (Session)thread.get(); //先从线程本地变量中得到要被关的session,然后将线程置空,然后再把session关掉!
         //当然也可以先关掉session,然后再把线程置空,这是一样的。
 thread.set(null);
 if(s!=null) s.close();
}
注意:session.close()被调用后,是会话资源被关闭了,但是java虚拟机里面的引用仍然指向了那个对象

因为如果使用session.close()的话,session结束了,但是线程还没有结束呢,在线程本地变量中的session对象也被关了,
但是注意session对象仍然存在!!!
但是如果之后别人再次调用currentSession()方法的话,得到的session是已经被关闭的session,必然会有问题

我可以把s置为null值,但是注意的是thread必须设为null值,也就是thread.set(null)必不可少!因为currentSession()方法中,
有一个Session s = (Session)thread.get()语句,如果thread没有被置空的话,那么仍然会取出那个已经被关闭的对象!!这是
不能允许的,所以要把thread置空才行,不能简单的只是关闭session就完了。

 

 

 


 

原创粉丝点击