1. 程式人生 > 實用技巧 >Spring框架——JDBC

Spring框架——JDBC

Spring與JDBC

資料庫配置

在beans.xml配置jdbc資料庫

	<!-- 資料來源 -->
	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName">
			<value>com.mysql.jdbc.Driver</value>
		</property>
		<property name="url">
			<value>jdbc:mysql://localhost:3306/mytest_db</value>
		</property>
		<property name="username">
			<value>root</value>
		</property>
		<property name="password">
			<value></value>
		</property>
	</bean>

JdbcTemplate

功能

JdbcTemplate類是Spring對JDBC支援類庫中的核心類

  • 建立和釋放資源
  • 執行SQL語句、儲存過程,並通過ResultSet來返回資料

在beans.xml配置

將dataSource依賴注入jdbcTemplate,指定執行操作的資料庫

	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>

用法

  1. 增刪改
this.jdbcTemplate.update("insert into book(title,price) values(?,?)", book.getTitle(),book.getPrice());
  1. 返回自增值的增刪改
		final String sql = "insert into book(title,price) values(?,?)";
		KeyHolder keyHolder = new GeneratedKeyHolder();
		this.jdbcTemplate.update(new PreparedStatementCreator() {
			
			@Override
			public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
				PreparedStatement pstm = con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
				pstm.setString(1, book.getTitle());
				pstm.setInt(2, book.getPrice());
				return pstm;
			}
		}, keyHolder);
		int key = keyHolder.getKey().intValue();
		System.out.println(key);
  1. 批處理
		final String sql = "delete from book where id = ?";
		this.jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
			
			@Override
			public void setValues(PreparedStatement pstm, int index) throws SQLException {
				pstm.setInt(1, ids[index]);
			}
			
			@Override
			public int getBatchSize() {
				return ids.length;
			}
		});
  1. 查詢

在Dao類中使用

@Repository

允許元件掃描來發現和配置自定義DAO
在類中配置該註解表示資料持久層

@Resource

持久化源,資料來源DataSource
依賴注入,獲取JdbcTemplate

@Repository
public class BookDaoImpl {
	
	@Resource
	private JdbcTemplate jdbcTemplate;
	
	public List<String> find(){
		return this.jdbcTemplate.queryForList("select name from menu", String.class);
	}
	
	public List<Menu> findAll(){
		return this.jdbcTemplate.query("select * from menu", new RowMapper<Menu>() {
					public Menu mapRow(ResultSet rs, int rowNum) throws SQLException{
						Menu m = new Menu();
						m.setId(rs.getInt(1));
						m.setName(rs.getString(2));
						m.setParentId(rs.getInt(3));
						return m;
					}
				});
	}
	
	public Menu findById(int id) {
		return this.jdbcTemplate.queryForObject("select * from menu where id = ?",
				new Object[] {id},
				new RowMapper<Menu>() {
					public Menu mapRow(ResultSet rs, int rowNum) throws SQLException{
						Menu m = new Menu();
						m.setId(rs.getInt(1));
						m.setName(rs.getString(2));
						m.setParentId(rs.getInt(3));
						return m;
					}
				});
	}
	
	
	public int countParentIdNull() {
		int count = this.jdbcTemplate.queryForObject("select count(id) from menu where parentId is not null", Integer.class);
		return count;
	}
	
	public void saveBook(Book book) {
		this.jdbcTemplate.update("insert into book(title,price) values(?,?)", 
				book.getTitle(), book.getPrice());
		final String sql = "insert into book(title,price) values(?,?)";
		KeyHolder keyHolder = new GeneratedKeyHolder();
		this.jdbcTemplate.update(new PreparedStatementCreator() {
			
			@Override
			public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
				PreparedStatement pstm = con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
				pstm.setString(1, book.getTitle());
				pstm.setInt(2, book.getPrice());
				return pstm;
			}
		}, keyHolder);
		int key = keyHolder.getKey().intValue();
		System.out.println(key);
		
	}
	
	public void batchDelete(int[] ids) {
		final String sql = "delete from book where id = ?";
		this.jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
			
			@Override
			public void setValues(PreparedStatement pstm, int index) throws SQLException {
				pstm.setInt(1, ids[index]);
			}
			
			@Override
			public int getBatchSize() {
				return ids.length;
			}
		});
	}

}

在Service類中

@Service

在類中配置該註解表示業務邏輯層

@Resource

依賴注入,將Dao依賴注入進Service,獲取Dao

@Service
public class BookServiceImpl {
	
	@Resource
	private BookDaoImpl bookDaoImpl;
	
	public void addBook(Book book) {
		this.bookDaoImpl.saveBook(book);
	}
	
	public void batchDelete(int[] ids) {
		this.bookDaoImpl.batchDelete(ids);
	}
	
	public int count() {
		return this.bookDaoImpl.countParentIdNull();
	}
	
	public Menu findById(int id) {
		return this.bookDaoImpl.findById(id);
	}
	
	public List<Menu> findAll(){
		return this.bookDaoImpl.findAll();
	}
	
	public List<String> find(){
		return this.bookDaoImpl.find();
	}

}

Spring與事務

概念

事務是一組原子操作的工作單元

  • 原子性(Atomic)

事務由一個或多個行為捆綁在一起組成一個單獨的工作單元,原子性保證事務中的所有操作要麼都發生,要麼都不發生

  • 一致性(Consistent)

一旦一個事務結束了(不管成功與否),系統所處的狀態和它的業務規則是一致的,也就是說資料應當不會被破壞

  • 隔離性(Isolated)

事務應該允許多名使用者操作同一個資料,一名使用者的操作不會和其他使用者的操作相混淆(隔離級別)

  • 永續性(Durable)

一旦事務完成,事務的結果應該持久化,用來保證即使系統崩潰也不會破壞事務的結果

Spring框架提供了程式設計式事務管理宣告式事務管理

程式設計式事務

  1. 可以清楚地控制事務的邊界
  2. 可自行實現事務開始時間、結束時間、撤消操作的時機等
  3. 可以實現細粒度的事務控制

beans.xml

	<!-- 事務 -->
	<bean id="transactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>

宣告式事務

  1. 事務管理的API不介入程式,最符合一個非侵入型輕量級容器的理想
  2. Spring Framework的宣告式事務管理是建立在Spring的面向切面程式設計(aspect-oriented programming, AOP) 上的
  3. Spring配置檔案中關於事務配置總是由三個組成部分,分別是DataSource、TransactionManager和代理機制這三部分,無論哪種配置方式,一般變化的只是代理機制這部分