Spring對數據庫的操作在jdbc上面做了基本的封裝,讓開發者在操作數據庫時只需關注SQL語句和查詢
結果處理器,即可完成功能(當然,只使用JdbcTemplate,還不能擺脫持久層實現類的編寫)。
在配合spring的IoC功能,可以把DataSource注冊到JdbcTemplate之中。同時利用spring基於
aop的事務即可完成簡單的數據庫CRUD操作。
JdbcTemplate的限定命名為org.springframework.jdbc.core.JdbcTemplate。要使用
JdbcTemlate需要導入spring-jdbc和spring-tx兩個坐標。
方法說明:
execute方法:
可以用於執行任何SQL語句,一般用於執行DDL語句;
update方法及batchUpdate方法:
update方法用於執行新增、修改、刪除等語句;batchUpdate方法用於執行批處理相關語
句;
query方法及queryForXXX方法:
用於執行查詢相關語句;
call方法:
用於執行存儲過程、函數相關語句。
使用案例
項目結構:
項目代碼
POM.XML
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.45</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
</dependencies>
實體類:
public class Account implements Serializable {
private Integer id;
private String name;
private Double money;
//省略getter setter
}
public class Userinfo implements Serializable {
private Integer id;
private byte[] images; // 對應mysql數據庫longBlob類型
private String description; // 對應表的longText類型
// 省略getter setter
}
相對應account表和userinfo表
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring_ioc
jdbc.username=root
jdbc.password=admin
jbbc配置類:
public class JdbcConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
/**
* 創建數據源並存入Ioc容器
* @return
*/
@Bean
public DataSource createDataSource(){
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
/**
* 創建JdbcTemplate對象
* @param dataSource
* @return
*/
@Bean
public JdbcTemplate createJdbcTemplate(DataSource dataSource){
return new JdbcTemplate(dataSource);
}
// 操作clob和blob
@Bean
public LobHandler createLobHandler(){
return new DefaultLobHandler();
}
}
主配置類:
@Configuration
@Import(JdbcConfig.class)
@PropertySource("classpath:jdbc.properties")
public class SpringConfiguration {
}
測試類:
/**
*注釋部分為不同寫法
* 測試JdbcTemplate的使用
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfiguration.class)
public class SpringJdbcTemplateTest {
@Autowired
private JdbcTemplate jdbcTemplate;
@Test
public void testSave(){
jdbcTemplate.update("insert into account(money,name)values(?,?)",6789d,"userTest");
}
@Test
public void testUpdate(){
jdbcTemplate.update("update account set name=?,money=? where id=?","testZZZ",23456d,3);
}
@Test
public void testDelete(){
jdbcTemplate.update("delete from account where id = ? ",4);
}
@Test
public void testFindOne(){
// List<Account> accounts = jdbcTemplate.query("select * from account where id = ?",new BeanPropertyRowMapper<Account>(Account.class),1);
// System.out.println(accounts.isEmpty()?"empty":accounts.get(0));
// Account account = jdbcTemplate.queryForObject("select * from account where id = ?",new BeanPropertyRowMapper<Account>(Account.class),1);
// System.out.println(account);
Account account = jdbcTemplate.query("select * from account where id = ?", new ResultSetExtractor<Account>() {
@Override
public Account extractData(ResultSet rs) throws SQLException, DataAccessException {
Account account1 = null;
//1.判斷結果集能往下走
if(rs.next()){
account1 = new Account();
account1.setId(rs.getInt("id"));
account1.setName(rs.getString("name"));
account1.setMoney(rs.getDouble("money"));
}
return account1;
}
}, 1);
System.out.println(account);
}
@Test
public void testFindAll(){
List<Account> accountList = jdbcTemplate.query("select * from account where money > ?",new BeanPropertyRowMapper<Account>(Account.class),999d);
for(Account account : accountList){
System.out.println(account);
}
}
@Test
public void testFindCount(){
Integer count = jdbcTemplate.queryForObject("select count(*) from account where money > ?",Integer.class,999d);
System.out.println(count);
}
@Test
public void testQueryForList(){
/**
* 得到某個特定類型的集合。類型是方法的第二個參數指定的
*/
List<Double> list = jdbcTemplate.queryForList("select money from account where money > ?",Double.class,999d);
for(Double money : list){
System.out.println(money);
}
// List<Map<String,Object>> list = jdbcTemplate.queryForList("select * from account where money > ? ",999d);
// for(Map<String,Object> map : list){
// for(Map.Entry<String,Object> me : map.entrySet())
// System.out.println(me.getKey()+","+me.getValue());
// }
}
@Test
public void testQueryForMap(){
Map<String,Object> map = jdbcTemplate.queryForMap("select * from account where id = ?",1);
for(Map.Entry<String,Object> me : map.entrySet()) {
System.out.println(me.getKey()+","+me.getValue());
}
}
@Test
public void testQueryForRowSet(){
SqlRowSet rowSet = jdbcTemplate.queryForRowSet("select * from account where money > ?",999d);
System.out.println(rowSet);
while(rowSet.next()){
String name = rowSet.getString("name");
System.out.println(name);
}
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfiguration.class)
public class SpringLobTest {
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private LobHandler lobHandler;
@Test
public void testWrite(){
try {
//准備images的字節數組
Resource resource = new FileSystemResource("E:\\6.jpg");
byte[] images = FileCopyUtils.copyToByteArray(resource.getFile());
//准備description
String description = "BLOB (binary large object),二進制大對象,是一個可以存儲二進制文件的容器。\n" +
"在計算機中,BLOB常常是數據庫中用來存儲二進制文件的字段類型。\n" +
"BLOB是一個大文件,典型的BLOB是一張圖片或一個聲音文件,\n" +
"由於它們的尺寸,必須使用特殊的方式來處理(例如:上傳、下載或者存放到一個數據庫)。\n" +
"根據Eric Raymond的說法,處理BLOB的主要思想就是讓文件處理器(如數據庫管理器)不去理會文件是什么,\n" +
"而是關心如何去處理它。但也有專家強調,這種處理大數據對象的方法是把雙刃劍,\n" +
"它有可能引發一些問題,如存儲的二進制文件過大,會使數據庫的性能下降。\n" +
"在數據庫中存放體積較大的多媒體對象就是應用程序處理BLOB的典型例子。";
//1.創建Userinfo
Userinfo userinfo = new Userinfo();
userinfo.setImages(images);
userinfo.setDescription(description);
jdbcTemplate.execute("insert into userinfo(images,description)values(?,?)", new AbstractLobCreatingPreparedStatementCallback(lobHandler) {
@Override
protected void setValues(PreparedStatement ps, LobCreator lobCreator) throws SQLException, DataAccessException {
lobCreator.setBlobAsBytes(ps, 1, userinfo.getImages());
lobCreator.setClobAsString(ps, 2, userinfo.getDescription());
}
});
}catch (Exception e){
e.printStackTrace();
}
}
@Test
public void testRead(){
// Userinfo userinfo = jdbcTemplate.queryForObject("select * from userinfo where id = ?",new BeanPropertyRowMapper<Userinfo>(Userinfo.class),1);
Userinfo userinfo = jdbcTemplate.query("select * from userinfo where id = ?", new ResultSetExtractor<Userinfo>() {
@Override
public Userinfo extractData(ResultSet rs) throws SQLException, DataAccessException {
Userinfo userinfo1 = null;
if(rs.next()){
userinfo1 = new Userinfo();
userinfo1.setId(rs.getInt("id"));
userinfo1.setImages(lobHandler.getBlobAsBytes(rs,"images"));
userinfo1.setDescription(lobHandler.getClobAsString(rs,"description"));
}
return userinfo1;
}
}, 1);
System.out.println(userinfo);
}
}
具名參數使用
在經典的 JDBC 用法中, SQL 參數是用占位符 ? 表示,並且受到位置的限制. 定位參數的問題在於,一旦參數的順序發生變化, 就必須改變參數綁定.在 Spring JDBC 框架中, 綁定 SQL 參數的另一種選擇是使用具名參數(namedparameter).那么什么是具名參數?具名參數: SQL 按名稱(以冒號開頭)而不是按位置進行指定. 具名參數更易於維護, 也提升了可讀性. 具名參數由框架類在運行時用占位符取代具名參數只NamedParameterJdbcTemplate 中得到支持。NamedParameterJdbcTemplate可以使用全部jdbcTemplate方法。
在jdbcConfig中加入組件
@Bean
public NamedParameterJdbcTemplate createNamedParameterJdbcTemplate(JdbcTemplate jdbcTemplate){
return new NamedParameterJdbcTemplate(jdbcTemplate);
}
測試類:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfiguration.class)
public class SpringNamedParameterJdbcTemplateTest {
@Autowired
private NamedParameterJdbcTemplate jdbcTemplate;
@Test
public void testFind(){
Map<String,Object> map = new HashMap<>();
map.put("id",1);
Account account = jdbcTemplate.queryForObject("select * from account where id = :id",map,new BeanPropertyRowMapper<Account>(Account.class));
System.out.println(account);
}
@Test
public void testSave(){
Account account = new Account();
account.setName("NamedParameterJdbcTemplate");
account.setMoney(12345d);
BeanMap beanMap = BeanMap.create(account);
jdbcTemplate.update("insert into account(name,money)values(:name,:money)",beanMap);
}
}
