使用Spring进行JDBC数据的访问(上)

4.1使用普通的JDBC所带来的问题

 

4.2 引入Spring 的JDBC支持

三种数据库访问操作:

1、Template Method模式的实用程序类(JdbcTemplate,NamedParameterJdbcTemplate),删除程序中的代码块,处理资源清理,完成JDBC操作。

2、使用SimpleJdbcInsert和SimpleJdbcCall之类的类以及数据库元数据,简化查询。

3、通过使用MappingSqlQuery ,SqlUpdate,Storedprocedure类,将数据库操作表示为可以重复使用的java对象。

 

4.2.1 管理JDBC连接

1、DriverManager 

2、DataSource,这种更好是一个广义的连接工厂,它能让我们隐藏数据库连接参数、连接池以及来自应用程序的事物管理问题。

   (1)、创建项目

     (2) 、pom.xml文件添加

<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>4.0.5.RELEASE</version>
</dependency>

    (3)创建所需要的数据库

  (4)定义一个dataSource Bean

@Configuration
public class Ch4Configuration {
  @Bean
  public DataSource dataSource(){
	  DriverManagerDataSource dataSource = new DriverManagerDataSource();
	  dataSource.setDriverClassName("com.mysql.jdbc.Driver");
	  dataSource.setUrl("jdbc:mysql://localhost:3306/fscdb");
	  dataSource.setUsername("root");
	  dataSource.setPassword("123456");
	  return dataSource;
  }
}

 

同样也可以使用SingleConnectionDataSource 创建dataSource对象

(7)Main

 AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(Ch4Configuration.class);
	 DataSource dataSource=applicationContext.getBean("dataSource",DataSource.class);
	 Connection connection =dataSource.getConnection();
	 System.out.println(connection.isClosed());
	 connection.close();
	 System.out.println(connection.isClosed());

(8)所需的jar包

4.2.2 配置和使用Spring的JDBC支持

(1)创建对象以及接口


public class Account {

	private long id;
	private String ownername;
	private double balance;
	private Date accessTime;
	private boolean locked;
//geter、seter省略
	
}
public interface AccountDao {
   public void insert(Account account);
   public void update(Account account);
   public void update(List<Account> accounts);
   public void delete(long accountId);
   public Account find(long accountId);
   public List<Account> find(List<Long> accountIds);
   public Account find(String ownerName);
   public List<Account> find(boolean locked);
}

(2)实现接口:public class AccountDaoJdbcImpl implements AccountDao 

public class AccountDaoJdbcImpl implements AccountDao {
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	    namedParameterJdbcTemplate=new NamedParameterJdbcTemplate(jdbcTemplate);
		
	}
//method implementations
}

(3)使用dataSource Bean 完成jdbcTemplat Bean 依赖

  (4)通过使用AccountDaoJdbcImpl类创建accountDao Bean ,并将jdbcTemplate Bean注入其中

 

@Configuration
public class Ch4Configuration {
  @Bean
  public DataSource dataSource(){
	  DriverManagerDataSource dataSource = new DriverManagerDataSource();
	  dataSource.setDriverClassName("com.mysql.jdbc.Driver");
	  dataSource.setUrl("jdbc:mysql://localhost:3306/test");
	  dataSource.setUsername("root");
	  dataSource.setPassword("123456");
	  return dataSource;
  }
  
  @Bean
  public JdbcTemplate jdbcTemplate(){
	  JdbcTemplate jdbcTemplate=new JdbcTemplate();
	  jdbcTemplate.setDataSource(dataSource());
	  return jdbcTemplate;
  }
    
  @Bean
  public AccountDao accountDao() throws SQLException{
	  AccountDaoJdbcImpl accountDao = new AccountDaoJdbcImpl();
	  accountDao.setJdbcTemplate(jdbcTemplate());
	  return accountDao;
  }
 
  
}

 (5)在main方法中对accountBean的查找

 AnnotationConfigApplicationContext applicationContext=
new AnnotationConfigApplicationContext(Ch4Configuration.class);
	 AccountDao accountDao=applicationContext.getBean(AccountDao.class);

4.3使用Spring执行数据库的访问操作

使用jdbcTemplate更为特殊NameParameterjdbcTemplate来解释各种数据访问操作是如何被执行的。还有SimpleJdbcCall简化使用数据库元数据的查询,使用MappingSqlQuery、SqlUpdate、StoredProcedure类说明如何将SQL操作模块化为一个java对象并反复使用。

4.3.1执行查询

JdbcTemplat通过不同重载版本提供了各种方法执行查询,通常使用qurey()、qureForObject()、queryForList(..)、queryForMap(..)、queryForObject(..)、(接收不同输入参数、比如查询字符串、查询输入参数值、类型、结果对象类型等)

find方法


		 	//JdbcTemplate.queryForObject().该方法接收一个SQL查询、一个RowMapper对象以及一个可变参数对象作为查询输入参数。
	
		   return jdbcTemplate.queryForObject(
				"select id,owner_name,balance,access_time,locked from account where id =?",
				new  RowMapper<Account>(){
					//RowMapper接口创建一个匿名类。其mapRow(..)方法返回一个Account对象
					public Account mapRow(ResultSet rs, int rowNum)
							throws SQLException {
					 Account account = new Account();
					 account.setId(rs.getLong("id"));
					 account.setOwnername(rs.getString("owner_name"));
					 account.setBalance(rs.getDouble("balance"));
					 account.setAccessTime(rs.getTimestamp("access_time"));
					 account.setLocked(rs.getBoolean("locked"));
					 return account;
					};
				}
				, accountId); 

(4)插入数据 INSERT INTO account(id,owner_name,balance,access_time,locked) VALUES(100,'john doe',10.0,'2014-01-01',FALSE);

(5)在主方法中获取记录

 AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(Ch4Configuration.class);
	 AccountDao accountDao=applicationContext.getBean(AccountDao.class);
	 Account account =accountDao.find(100L);
	 System.out.println(account.getId());
	 System.out.println(account.getOwnername());
	 System.out.println(account.getBalance());
	 System.out.println(account.getAccessTime());
	 System.out.println(account.isLocked());
	 
	 

4.3.2使用命名参数进行查询

NamedParameterJdbcTemplate实际上封装了JdbcTemplate,所以几乎所有的艰苦工作都是由JdbcTemplate来完成

(1)添加NamedParameterJdbcTemplate属性

public class AccountDaoJdbcImpl implements AccountDao {
	
	private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
        private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	    namedParameterJdbcTemplate=new NamedParameterJdbcTemplate(jdbcTemplate);
		
	}
}

(2)使用NamedParameterJdbcTemplate实现find而不是JdbcTemplate。

@Override
	public Account find(String ownerName) {
		String sql="select id,owner_name,balance,access_time,locked from account where owner_name=:ownername";
		//JdbcTemplate.queryForObject().该方法接收一个SQL查询、一个RowMapper对象以及一个可变参数对象作为查询输入参数。
		return namedParameterJdbcTemplate.
				queryForObject
				(sql, Collections.singletonMap("ownername", ownerName), new RowMapper<Account>() {
				//RowMapper接口创建一个匿名类。其mapRow(..)方法返回一个Account对象
					@Override
					public Account mapRow(ResultSet rs, int rowNum)
							throws SQLException {
						Account account = new Account();
						account.setId(rs.getLong("id"));
						account.setOwnername(rs.getString("owner_name"));
						account.setBalance(rs.getDouble("balance"));
						account.setAccessTime(rs.getTimestamp("access_time"));
						account.setLocked(rs.getBoolean("locked"));
						return account;
					}
					
				});
	}

4.3.3 使用in子句编写查询

4.3.4 在JdbcTemplate中使用PrepareStatements

相对于每次动态的创建查询字符串,使用PrepareStatements的另一个好处是免糟sql注入攻击

(1)在JdbcTemplate.query()方法使用PrepareStatementsCreator实例来获取PrepareStatement对象。通过使用PrepareStatementsCreatorFactory类,可以使用不同的参数创建多个PrepareStatement对象。

@Override
	public List<Account> find(boolean locked) {
		 String sql="select * from account where locked=?";
		 PreparedStatementCreatorFactory preparedStatementCreatorFactory=new PreparedStatementCreatorFactory(sql, new int[]{Types.BOOLEAN});
		return jdbcTemplate.query(preparedStatementCreatorFactory.newPreparedStatementCreator(new Object[]{locked}),
				new RowMapper<Account>() {
			         public Account mapRow(ResultSet rs, int rowNum) throws SQLException {
			        		Account account = new Account();
							account.setId(rs.getLong("id"));
							account.setOwnername(rs.getString("owner_name"));
							account.setBalance(rs.getDouble("balance"));
							account.setAccessTime(rs.getTimestamp("access_time"));
							account.setLocked(rs.getBoolean("locked"));
							return account;
			        	 
			         };
				}
				
				);
	}

为了可以作为回调的接口使用,在JdbcTemplate.query()方法还接收创建了自PrepareStatementSetter接口的实例。该实例用来在PrepareStatement对象上设置参数值。JdbcTemplate创建PrepareStatement,而该回调仅负责设置参数值。

@Override
	public List<Account> find(boolean locked) {
		 String sql="select * from account where locked=?";
		 PreparedStatementCreatorFactory preparedStatementCreatorFactory=new PreparedStatementCreatorFactory(sql, new int[]{Types.BOOLEAN});
		return jdbcTemplate.query(preparedStatementCreatorFactory.newPreparedStatementCreator(new Object[]{locked}),
				new RowMapper<Account>() {
			         public Account mapRow(ResultSet rs, int rowNum) throws SQLException {
			        		Account account = new Account();
							account.setId(rs.getLong("id"));
							account.setOwnername(rs.getString("owner_name"));
							account.setBalance(rs.getDouble("balance"));
							account.setAccessTime(rs.getTimestamp("access_time"));
							account.setLocked(rs.getBoolean("locked"));
							return account;
			        	 
			         };
				}
				
				);
	}

4.3.5 插入、更新、删除

(1)插入

@Override
	public void insert(Account account) {
		String sql="insert into account (owner_name,balance,access_time,locked)values (?,?,?,?)";
		PreparedStatementCreatorFactory psCreatorFactory=new PreparedStatementCreatorFactory(sql, 
				new int[]{
				Types.VARCHAR,Types.DOUBLE,Types.TIMESTAMP,Types.BOOLEAN
		}
				);
		KeyHolder keyHandler=new GeneratedKeyHolder();
		int count = jdbcTemplate.update(psCreatorFactory.newPreparedStatementCreator(new Object[]{
			account.getOwnername(),account.getBalance(),account.getAccessTime(),account.isLocked()	
		}),keyHandler);
		
		 if(count!=1)throw new InsertFailedException("count insert account ");
		 account.setId(keyHandler.getKey().longValue());
	}

(2)更新

@Override
	public void update(Account account) {
		String sql="UPDATE account SET owner_name=?,balance=?,access_time=?,locked=? WHERE id=?";
		int count=jdbcTemplate.update(sql, 
				account.getOwnername(),account.getBalance(),account.getAccessTime(),account.isLocked(),account.getId()
				);
        if(count!=1)throw new InsertFailedException("Cannot update account ");
	}

(3)删除


	@Override
	public void delete(long accountId) {
		int count=jdbcTemplate.update("delete from account where id=?",accountId) ;
		  if(count!=1)throw new InsertFailedException("Cannot delete account ");
	}

4.3.6调用存储过程和存储函数(p112)

4.3.7执行批处理操作

 可以将多个更新操作组合在一起,并且在一个由JdbcTemplate创建的PrepareStatement对象中执行这些操作,该过程被称为批处理。批处理操作可以减少往返数据库的次数,有助于提高数据库的访问性能。为此提供了一个batchUpdate(..)方法。

4.3.8 处理BLOB和CLOB对象(p124)

4.3.9 访问特定供应商的JDBC方法(p125)

4.3.10 执行ddl操作

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值