學了Spring操做 JDBC 以後,固然要學怎麼整合Hibernate了,這個例子的整合步驟,xml配置等等均可以應用到實際開發中,畢竟如今企業開發絕大多數都是SpringMvc模式下配合Hibernate來搭建項目的,因此本文從細節出發,詳細介紹每個步驟。。java
需求:數據表結構:account表,用戶帳號表。book表,書籍信息表mysql
項目結構: spring
hibernate配置文件sql
<hibernate-configuration> <session-factory> <!-- 配置hibernate的基本屬性 --> <!-- 數據源配置到ioc容器中,因此在此不須要再配置 --> <!-- 關聯的.hbm.xml 也在ioc容器配置SessionFactory實例時進行配置 --> <!-- 配置Hibernate的基本屬性:方言,sql顯示,格式化,自動建表,生成數據表的策略以及二級緩存等。。 --> <!-- 使用的數據庫方言 --> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <!-- 自動建立表 --> <property name="hbm2ddl.auto">update</property> <!-- 控制檯打印sql語句 --> <property name="show_sql">true</property> <!-- 格式化sql語句 --> <property name="format_sql">true</property> </session-factory> </hibernate-configuration>
數據庫配置信息文件:db.properties數據庫
jdbc.user=root jdbc.password= jdbc.driverClass=com.mysql.jdbc.Driver jdbc.jdbcUrl=jdbc:mysql:///testspring jdbc.initPoolSize=5 jdbc.maxPoolSize=10
Spring的配置文件express
<!-- 配置數據源 --> <!-- 導入資源文件 --> <context:property-placeholder location="classpath:db.properties" /> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="user" value="${jdbc.user}"></property> <property name="password" value="${jdbc.password}"></property> <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property> <property name="driverClass" value="${jdbc.driverClass}"></property> <property name="initialPoolSize" value="${jdbc.initPoolSize}"></property> <property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property> </bean> <!-- 自動掃描 --> <context:component-scan base-package="com.*"></context:component-scan> <!-- 整合Hibernate的SessionFactory的實例:經過Spring提供的LocaltionSessionFactoryBean進行配置 --> <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <!-- 配置數據源的屬性 --> <property name="dataSource" ref="dataSource"></property> <!-- 配置hibernate配置文件的位置 --> <!-- <property name="configLocation" value="classpath:hibernate.cfg.xml"></property> --> <!-- 使用HibernatePropites屬性來配置Hibernate的基本配置 --> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop> <prop key="hibernate.hbm2ddl.auto">update</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.format_sql">true</prop> </props> </property> <!-- 自動掃描註解方式配置的hibernate類文件 --> <property name="packagesToScan"> <list> <value>com.entiy</value> </list> </property> </bean> <!-- 配置Spring 的聲明式事務 --> <!-- 1.配置事務管理器 --> <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"></property> </bean> <!-- 2.配置事務屬性,須要事務管理器 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="get*" read-only="true"/> <tx:method name="*"/> </tx:attributes> </tx:advice> <!-- 3.配置事務切點,並把切點和事務屬性相關聯起來 --> <aop:config> <aop:pointcut expression="execution(* com.service.*.*(..))" id="txPoincut"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPoincut"/> </aop:config> </beans>
在ApplicationContext.xml文件中,咱們能夠引用Hibernate的配置文件來配置Hibernate的基本信息,也能夠直接 使用HibernatePropites屬性來配置Hibernate的基本配置,那麼hibernate.cfg.xml就能夠刪除不用了,上文是直接在ioc容器使用HibernatePropites屬性來配置的緩存
接口 BookShopI.java:session
public interface BookShopI { /** * 根據書的編號查找書的價格 * @param id 書的編號 * @return */ int findBookPriceById(String id); /** * 更新書的庫存 * @param id 書的編號 */ void updateBookStore(String id); /** * 更新用戶的帳戶餘額 * @param userName 用戶名 * @param price 餘額 */ void updateUserAccount(String userName,int price); }
接口的實現 BookShopImpl:ide
@Repository public class BookShopImpl implements BookShopI { @Autowired private SessionFactory sessionFactory; // 獲取和當前線程綁定的session private Session getSession() { return sessionFactory.getCurrentSession(); } @Override public int findBookPriceById(String id) { String hql = "select b.price from Book b where b.bookId = :params "; Query query = getSession().createQuery(hql).setParameter("params", id); int price = (int) query.uniqueResult(); return price; } @Override public void updateBookStore(String id) { // 驗證庫存是否充足 String checkHql = "select b.store from Book b where b.bookId=:params "; Query query = getSession().createQuery(checkHql).setParameter("params", id); int store = (int) query.uniqueResult(); if (store == 0) { throw new BookStoreException("庫存不足"); } String hql = "update Book b set b.store = b.store -1 where b.bookId=:params "; getSession().createQuery(hql).setParameter("params", id).executeUpdate(); } @Override public void updateUserAccount(String userName, int price) { // 驗證餘額是否充足 String checkHql = "select a.balance from Account a where a.userName=:params "; Query query = getSession().createQuery(checkHql).setParameter("params", userName); float balance = (float) query.uniqueResult(); if (balance < price) { throw new UserPriceException("餘額不足"); } String hql = "update Account a set a.balance=a.balance - '" + price + "' where a.userName=:params "; getSession().createQuery(hql).setParameter("params", userName).executeUpdate(); } }
兩個實體類:這裏使用的是註解的方式測試
Account
@Entity @Table(name="account") public class Account implements Serializable { private Long id; private String userName; private float balance; @Id @GeneratedValue(strategy=GenerationType.AUTO) public Long getId() { return id; } public void setId(Long id) { this.id = id; } @Column(name="username") public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } @Column(name="balance") public float getBalance() { return balance; } public void setBalance(float balance) { this.balance = balance; } }
**Book **
@Entity @Table(name="book") public class Book implements Serializable { private Long id; private String bookName; private String bookId; private int price; private int store; @Id @GeneratedValue(strategy=GenerationType.AUTO) public Long getId() { return id; } public void setId(Long id) { this.id = id; } @Column(name="bookname") public String getBookName() { return bookName; } public void setBookName(String bookName) { this.bookName = bookName; } @Column(name="bookid") public String getBookId() { return bookId; } public void setBookId(String bookId) { this.bookId = bookId; } @Column(name="price") public int getPrice() { return price; } public void setPrice(int price) { this.price = price; } @Column(name="store") public int getStore() { return store; } public void setStore(int store) { this.store = store; } }
兩個自定義異常:
BookStoreException
public class BookStoreException extends RuntimeException{ public BookStoreException() { super(); // TODO Auto-generated constructor stub } public BookStoreException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); // TODO Auto-generated constructor stub } public BookStoreException(String message, Throwable cause) { super(message, cause); // TODO Auto-generated constructor stub } public BookStoreException(String message) { super(message); // TODO Auto-generated constructor stub } public BookStoreException(Throwable cause) { super(cause); // TODO Auto-generated constructor stub } }
UserPriceException
public class UserPriceException extends RuntimeException { public UserPriceException() { super(); // TODO Auto-generated constructor stub } public UserPriceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); // TODO Auto-generated constructor stub } public UserPriceException(String message, Throwable cause) { super(message, cause); // TODO Auto-generated constructor stub } public UserPriceException(String message) { super(message); // TODO Auto-generated constructor stub } public UserPriceException(Throwable cause) { super(cause); // TODO Auto-generated constructor stub } }
service層:
** 接口:UserByBookServiceI**
public interface UserByBookServiceI { /** * 用戶買書 * * @param UserName * 用戶名 * @param bookId * 書的編號 */ void byBook(String userName, String bookId); /** * 用戶買多本書 * * @param userName * 用戶名 * @param bookIds * 書的編號集合 */ void byMoreBook(String userName, List<String> bookIds); }
實現:UserByBookServiceImpl
@Service("userByBookService") public class UserByBookServiceImpl implements UserByBookServiceI { @Autowired private BookShopI bookShopI; @Override public void byBook(String userName, String bookId) { //獲取書的價格 int price = bookShopI.findBookPriceById(bookId); //使書的庫存減1 bookShopI.updateBookStore(bookId); //更新用戶的帳戶餘額 bookShopI.updateUserAccount(userName, price); } @Override public void byMoreBook(String userName, List<String> bookIds) { // TODO Auto-generated method stub } }
最後測試主方法:
public class Main { private ApplicationContext ctx = null; private UserByBookServiceI userByBookService=null; { ctx = new ClassPathXmlApplicationContext("ApplicationContext.xml"); userByBookService = (UserByBookServiceI) ctx.getBean("userByBookService"); } @Test public void testDataSource() throws SQLException { DataSource dataSource = (DataSource) ctx.getBean("dataSource"); System.out.println(dataSource.getConnection()); } @Test public void byBook(){ userByBookService.byBook("admin", "1001"); } }
運行前數據:
account表 book表:
測試byBook()方法 控制檯:
運行後數據 account表
book表:
能夠看到操做數據是成功的,一樣的方法,byMoreBook方法也是能夠運行經過的,而且事務的回滾也是能夠成功的。