Spring4 學習系列之——整合基於註解的Hibernate實例

學了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方法也是能夠運行經過的,而且事務的回滾也是能夠成功的。

相關文章
相關標籤/搜索