Spring与Hibernate整合实现(SH框…

  先放图,本节的工程文件目录结构如下:
Spring与Hibernate整合实现(SH框架)

以及要导入的额外库文件(记得加上Hibernate库和SpringFramework的库):
Spring与Hibernate整合实现(SH框架)
其中:
aopalliance.jar
aspectjweaver-1.7.2.jar
可能需要到网上下载。随便百度个就行,蛮多人分享的。

  Spring与Hibernate两边结合在一起之后,Spring对Hibernate的一些启动操作进行了接管。毕竟Spring本身是一个管理类工厂的服务,而许多程序、应用的初始化操作,可以交给Spring来完成。
  于是,Hibernate里面的数据库地址、用户名、密码和操作参数等,统统交给Spring来接管了,我们无需担心。于是Hibernate.cfg.xml文件变得异常简洁。记得在上一节讲解Hibernate的时候,启动一个服务要写相当多的 启动代码

        Configuration cfg = new Configuration().configure();
        // 如果是hibernate4.0以前的版本,使用如下的方式创建SessionFactory对象
        // SessionFactory factory = cfg.buildSessionFactory();
        StandardServiceRegistryBuilder ssrb = new StandardServiceRegistryBuilder()
                .applySettings(cfg.getProperties());
        ServiceRegistry service = ssrb.build();
        SessionFactory factory = cfg.buildSessionFactory(service);
        
        Session session = factory.openSession();
        Transaction tx = session.beginTransaction();

然后才是 业务代码 (也就是功能代码):

        try {
            Student stu = (Student) session.get(Student.class, 1);
            stu.setName("lisi");
            tx.commit();
        } catch (Exception e) { 
            tx.rollback();
        } finally {
            session.close();
        }

  其实Hibernate只需要启动一次,然后整个项目都用一个或者两个实例就好根据线程的负载和锁的情况,别造成这个用了Hibernate,那个急着用又用不上又不能自己生成一个实例来用。所以具体怎么管理,怎么生成,或者什么时候用这些类的实例Configuration、StandardServiceRegistryBuilder、ServiceRegistry、SessionFactory等等就交给Spring框架来决定吧。我们看到,其实最主要的功能,集中在session处。如何保存、如何从数据库获取一行,都要靠session来执行。那么其实把冗余的初始化功能分离后,剩下的东西,写进一个功能模块里面,就成了 DAO (Data Access Object数据访问对象 )。我们来看这么一段代码:
文件BookDao.java
public interface BookDao{
    public String findBookById(int id);
    public void saveBook(Book book);
}
  可以看到,其实DAO类(或接口)就是一个封装了数据库操作的类(或接口)。DAO意味着封装了非常非常具体的数据库操作后,直接得到的服务。它可以是查询某个id得到这个id下的书名字符串,也可以是新建并保存一个书本条目。我们看到这个类使用了POJO类Book,Book的定义会在后面给出。具体怎么塞到数据库里面的,得由这个类的实现(implements)来进行:
文件BookDaoImpl.java
package dao_service;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import table.book.Book;

@Repository
public class BookDaoImpl implements BookDao{
    @Autowired
    private SessionFactory sessionFactory;
    //获取和当前线程绑定的Session
    private Session getSession(){
        return sessionFactory.getCurrentSession();
    }
    @Override public String findBookById(int id){
       
        //String hql="SELECT bookName from Book where id=?";//直接使用id=?会有问题
        //Query query=getSession().createQuery(hql).setInteger(0, id);
        String hql="SELECT bookName from Book where id=?0";//使用JPA方式,改为?0
                                                                                                    //即可用setParameter设置参数
        Query query=getSession().createQuery(hql);
        query.setParameter("0", id);
        
        String str= query.uniqueResult().toString();
        return str;
    }
    @Override public void saveBook(Book book){
        getSession().save(book);
    }
}
  从这个BookDaoImpl类实现,我们可以看到内置了一个SessionFactory。细心的同学会发现,有这个private类,却没有具体的实现,也没有setSessionFactory方法来设置它。它在saveBook()方法使用的时候不会是个空指针吗?
  奥妙就在这里,其实这个类内实例的导入,是由Spring来完成的。Spring跟Hibernate结合以后,提供了一系列自动化方法,比如可以自动搜索dao_service文件夹(也就是BookDao.java和BookDaoImpl.java存放的文件夹)下的类,根据关键词过滤来判断哪些是类的实现,根据方法名或者内部私有变量的名字,来判断装入何种类的实现(如具体的SessionFactory等等)。
  为了验证自动装配这一点,我们给它再套一个壳子,我们新建一个BookService类,里面提供的服务和内容跟BookDao类完全一样:
文件BookService.java
public interface BookService{
    public String findBookById(int id);
    public void saveBook(Book book);
}
然后我们建立一个实现,同样是在接口名后面加上Impl:
文件BookServiceImpl.java
package dao_service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import table.book.Book;

@Service
public class BookServiceImpl implements BookService
{
    @Autowired
    private BookDao bookDao;
    @Override
    public String findBookById(int id)
    {
        return bookDao.findBookById(id);
    }
    @Override
    public void saveBook(Book book)
    {
        bookDao.saveBook(book);
        
    }
}
  这个壳子啥都没做,仅仅是用了BookDao接口的方法来完成自己的方法。注意,在BookServiceImpl里所使用的不是BookDaoImpl的方法,而是BookDao,说明我们要想使用,必须得有个具体的实现。意味着整个过程必须有人来搞。这个人显然就是Spring。有兴趣的同学可以写一个计数器,看看Spring生成了多少个实例,并且都调用了哪个实例来使用(提示:用静态变量作计数器,则所有实例之间都可以共享了。不懂是否线程安全,为了准确计数,可以考虑加锁
  说了这么多,那么实体类(Entity Class)呢?在这里定义:
文件Book.java
package table.book;

//import org.hibernate.annotations.Entity;这个已经过时,用javax里面的entity代替
import javax.persistence.Entity;
import javax.persistence.Id;
import java.io.Serializable;
@Entity
public class Book implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    private Integer id;
    private String bookName;
    private String isbn;
    private int price;
    private int stock;

    public Book() {
    }
    public Book(Integer id, String bookName, String isbn, int price, int stock){
        super();
        this.id = id;
        this.bookName = bookName;
        this.isbn = isbn;
        this.price = price;
        this.stock = stock;
    }
    public Integer getId(){    return id;    }
    public void setId(Integer id){    this.id = id;    }
    public String getBookName(){    return bookName;    }
    public void setBookName(String bookName){    this.bookName = bookName;}
    public String getIsbn(){    return isbn;    }
    public void setIsbn(String isbn){    this.isbn = isbn;    }
    public int getPrice(){    return price;    }
    public void setPrice(int price){    this.price = price;    }
    public int getStock(){    return stock;    }
    public void setStock(int stock){    this.stock = stock;    }
}
  可以看到这个Book实体类里面有5个属性,对应着数据库表中5个列:id、bookname、isbn、price、stock。同理,给这个Book.java配置一个文件给hibernate读取:
文件Book.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">
<!-- Generated 2016-3-15 16:30:05 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
    <class name="table.book.Book" table="BOOK">
        <id name="id" type="java.lang.Integer">
            <column name="ID" />
            <generator class="native" />
        </id>
        <property name="bookName" type="java.lang.String">
            <column name="BOOK_NAME" />
        </property>
        <property name="isbn" type="java.lang.String">
            <column name="ISBN" />
        </property>
        <property name="price" type="int">
            <column name="PRICE" />
        </property>
        <property name="stock" type="int">
            <column name="STOCK" />
        </property>
    </class>
</hibernate-mapping>

接下来我们看看具体hibernate的配置文件:
文件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">
<!--
    十二月 08, 2016 12:48:02 下午 org.hibernate.internal.util.xml.DTDEntityResolver resolveEntity
    WARN: HHH000223: Recognized obsolete hibernate namespace http://hibernate.sourceforge.net/. 
    Use namespace http://www.hibernate.org/dtd/ instead. Refer to Hibernate 3.6 Migration Guide!
    如果对这个警告心烦的,可以把网址按照警告的要求来改。
-->
<hibernate-configuration>
    <session-factory>
        <!-- 配置Hibernate的基本属性 -->
        <!-- 1.数据源配置到IOC容器中 -->
        <!-- 2.关联的.hbm.xml也在IOC容器配置SessionFactory实例 -->
        <!-- 3.配置Hibernate的基本属性:方言,SQL显示及格式化,生成数据表的策略以及二级缓存 -->
        <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
        <property name="hibernate.show_sql">true</property>
        <property name="hbm2ddl.auto">update</property>
    </session-factory>
</hibernate-configuration>

明显少了很多东西。这些本该在hibernate.cfg.xml中的配置被转移到了Spring配置文件里面了:
文件applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd">
   <!--
        http://zghbwjl.blog.163.com/blog/static/120336672201092294943744/
        一看这个错误肯定是少包或者是包冲突,知道原因就找吧,根据这句: 
        java.lang.NoClassDefFoundError: org/aspectj/weaver/reflect/ReflectionWorld$ReflectionWorldException
        可以看出应该是少了aspectjweaver.jar这个jar包,加上就可以了。
    -->
    <!--
        context:component-scan base-package这是拿来扫描beans所在目录的
        所以要scan所定义的beans的目录。目前定义的就是DAO一些列bean
        http://blog.csdn.net/chenweihaoshuai/article/details/8036671
        目录不对会报错:
        org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'xx' is defined
    -->
    <context:component-scan base-package="dao_service"></context:component-scan>
    <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
        <!--
            尝试导入commons-dbcp2-2.1.1.jar包。解决这个BasicDataSource的问题
            然后确实要导入相应的pool2包
            这里可能是用来接管Hibernate的数据库定义的。账户、密码都不在hibernate.hbm.xml里面定义了
            参考资料:http://blog.csdn.net/a105421548/article/details/43016953
            密码等定义如下:
        -->
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <!--<property name="url" value="jdbc:mysql://localhost/test" />-->
        <property name="url" value="jdbc:mysql://localhost:3306/student_manager?useSSL=true" />
        <property name="username" value="root"></property>
        <property name="password" value="passwordOfRoot"></property>
    </bean>
    <!--
        常规的hibernate包缺失问题。项目事实的时候,最后SSH都分开,单独测试一下
        nested exception is java.lang.NoClassDefFoundError: javax/persistence/Entity
        缺少hibernate-jpa-2.1-api-1.0.0.Final.jar
        
        Cannot load JDBC driver class 'com.mysql.jdbc.Driver'
        缺少mysql-connector-java-5.1.39-bin.jar
    -->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" lazy-init="false">
        <!-- 注入datasource,给sessionfactoryBean内setdatasource提供数据源 -->
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation" value="classpath:configuration/hibernate.cfg.xml"></property>
        <!-- 
            加载实体类的映射文件位置及名称
            路径一定全都用斜杠table/book
public class MainClass {
    public static void main(String[] args) {
       
        ApplicationContext context;
        context = new ClassPathXmlApplicationContext("configuration/applicationContext.xml");
       
        DataSource dataSource = (DataSource) context.getBean(DataSource.class);
        System.out.println("dataSource.toString()=="+dataSource);

        
        BookService bookService;
        bookService = context.getBean(BookService.class);
        bookService.saveBook(new Book(1, "Android源码分析", "1002", 45, 10));
        bookService.saveBook(new Book(2, "iOS源码分析", "1012", 43, 20));
        
        String bookName = bookService.findBookById(1);
        System.out.println(bookName);
    }
}
  这么多代码写好以后,存储一本新书就非常简单了。首先Spring通过读取configuration里的xml文件得到配置好的context,然后context再通过getBean获取实体类,并用实体类进行数据库操作。我们可以看到多次运行后数据库里面加了很多条目。
  具体运行结果,上图:
Spring与Hibernate整合实现(SH框架)

Spring与Hibernate整合实现(SH框架)







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值