Spring JDBC簡介
先來看看一個JDBC的例子蜒秤。我們可以看到為了執(zhí)行一條SQL語句,我們需要創(chuàng)建連接莲趣,創(chuàng)建語句對象,然后執(zhí)行SQL饱溢,然后操縱結(jié)果集獲取數(shù)據(jù)喧伞。
try(Connection connection = DriverManager.getConnection(URL, USERNAME, PASSWORD)){
List<User> users = new ArrayList<>();
try (Statement statement = connection.createStatement()) {
try (ResultSet rs = statement.executeQuery("SELECT *FROM user")) {
while (rs.next()) {
User user = new User();
user.setId(rs.getInt(1));
user.setUsername(rs.getString(2));
user.setPassword(rs.getString(3));
user.setNickname(rs.getString(4));
user.setBirthday(rs.getDate(5));
users.add(user);
}
}
}
}
其實這些步驟中有很多步驟都是固定的,Spring JDBC框架將這些操作封裝起來, 我們只需要關(guān)注業(yè)務(wù)邏輯點即可潘鲫。在Spring JDBC框架中绿聘,我們要做的事情如下:
- 定義連接字符串參數(shù)。
- 指定SQL語句次舌。
- 聲明參數(shù)和參數(shù)類型熄攘。
- 每次迭代結(jié)果集的操作。
Spring會幫我們完成以下事情:
- 打開連接彼念。
- 準(zhǔn)備和執(zhí)行SQL語句挪圾。
- 在需要的情況下迭代結(jié)果集。
- 處理異常逐沙。
- 操作事務(wù)哲思。
- 關(guān)閉結(jié)果集、語句和數(shù)據(jù)庫連接吩案。
使用JdbcTemplate
JdbcTemplate是Jdbc框架最重要的類纽谒,提供了較為底層的Jdbc操作劲厌。其它幾個類都是在JdbcTemplate基礎(chǔ)上封裝了相關(guān)功能。
添加依賴
要在Gradle項目中使用Spring JDBC框架,添加如下一段井濒。由于Spring JDBC的主要類JdbcTemlate需要一個數(shù)據(jù)源用來初始化,所以還需要一個數(shù)據(jù)源的實現(xiàn)昏苏。
compile group: 'org.springframework', name: 'spring-jdbc', version: '4.3.5.RELEASE'
compile group: 'org.apache.commons', name: 'commons-dbcp2', version: '2.1.1'
如果要使用Spring框架的其他功能肴盏,可能還需要添加對應(yīng)的依賴。
創(chuàng)建Jdbc Template Bean
首先需要創(chuàng)建一個數(shù)據(jù)源Bean抱环。為了將配置分離壳快,我們先新建一個jdbc.properties
文件。
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.username=root
jdbc.password=12345678
然后創(chuàng)建一個Spring配置文件jdbc.xml
镇草。這里用到了<context:property-placeholder>
節(jié)點來導(dǎo)入其它配置文件眶痰。然后用這些屬性創(chuàng)建一個數(shù)據(jù)源Bean,然后再利用數(shù)據(jù)源Bean來創(chuàng)建一個JdbcTemplate梯啤。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="dataSource"/>
</bean>
<context:property-placeholder location="jdbc.properties"/>
</beans>
JdbcTemplate操作
注冊了JdbcTemplate之后竖伯,就可以將它注入到任何地方來使用了。首先它可以使用execute方法条辟,執(zhí)行任何SQL語句黔夭。這里創(chuàng)建了一個簡單的MySQL用戶表,只有主鍵和用戶名羽嫡。
jdbcTemplate.execute("CREATE TABLE user(id INT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(255) UNIQUE)");
它還可以使用update方法執(zhí)行增加本姥、更新和刪除操作。
jdbcTemplate.update("INSERT INTO user(name) VALUES(?)", "yitian");
jdbcTemplate.update("INSERT INTO user(name) VALUES(?)", "zhang2");
jdbcTemplate.update("UPDATE user SET name=? WHERE name=?", "zhang3", "zhang2");
jdbcTemplate.update("DELETE FROM user WHERE name=?", "zhang3");
查詢操作也很簡單杭棵,使用queryForObject方法婚惫,傳入SQL字符串和結(jié)果類型即可氛赐。
int count = jdbcTemplate.queryForObject("SELECT count(*) FROM user", Integer.class);
System.out.println("記錄數(shù)目是:" + count);
String name = jdbcTemplate.queryForObject("SELECT name FROM user WHERE id=1", String.class);
System.out.println("姓名是:" + name);
如果要查詢整條記錄也可以。Spring提供了一個接口RowMapper先舷,只需要實現(xiàn)該接口的mapRow方法艰管,即可將結(jié)果集的一條記錄轉(zhuǎn)化為一個Java對象,該方法的第二個參數(shù)是當(dāng)前行的行數(shù)蒋川。下面是一個RowMapper實現(xiàn)牲芋。
public class UserRowMapper implements RowMapper<User> {
@Override
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
return new User(rs.getInt(1), rs.getString(2));
}
}
User實體類對應(yīng)于上面創(chuàng)建表時簡單的用戶表(其他方法已省略)。
public class User {
private int id;
private String name;
}
實現(xiàn)了RowMapper接口之后捺球,我們就可以查詢一條記錄并轉(zhuǎn)化為Java對象了缸浦。
User user = jdbcTemplate.queryForObject("SELECT id,name FROM user WHERE id=?", new UserRowMapper(), 1);
System.out.println(user);
查詢多條記錄也可以,這時候需要使用query方法氮兵。
List<User> users = jdbcTemplate.query("SELECT id,name FROM usr", new UserRowMapper());
System.out.println(users);
還有一個通用方法queryForList裂逐,返回一個List,每一個元素都是一個Map泣栈,在Map中存放著列名和值組成的鍵值對卜高。
List<Map<String, Object>> results = jdbcTemplate.queryForList("SELECT id,name FROM user");
System.out.println(results);
使用NamedParameterJdbcTemplate
前面的JdbcTemplate提供了非常方便的JDBC操作封裝,但是在綁定參數(shù)的時候只能采用通配符?
方式以順序方式綁定參數(shù)南片。如果SQL語句比較復(fù)雜掺涛,參數(shù)比較多,那么這種方式顯得不太方便铃绒。因此Spring提供了一個更加方便的類NamedParameterJdbcTemplate鸽照,它可以以命名方式綁定SQL語句參數(shù)。NamedParameterJdbcTemplate在內(nèi)部使用一個JdbcTemplate颠悬,你也可以調(diào)用getJdbcOperations方法獲取底層的JdbcTemplate對象,然后用前面的方法進行基本操作定血。
創(chuàng)建NamedParameterJdbcTemplate和JdbcTemplate相同赔癌,只需要傳入一個數(shù)據(jù)源即可。
<bean id="namedParameterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
<constructor-arg ref="dataSource"/>
</bean>
NamedParameterJdbcTemplate和JdbcTemplate的大部分操作相同澜沟,這里僅介紹綁定命名參數(shù)的部分灾票。首先,SQL語句必須使用:參數(shù)名稱
的形式作為參數(shù)茫虽。然后刊苍,我們創(chuàng)建一個MapSqlParameterSource對象,它的內(nèi)部使用了一個Map保存的命名參數(shù)的名稱和值濒析。然后我們使用它的addValue方法傳遞需要的命名參數(shù)的名稱和值正什,這個方法還可以接受第三個參數(shù)指定參數(shù)類型,這個類型以java.sql.Types
的一些公共字段的形式給出号杏。最后婴氮,將MapSqlParameterSource傳遞給相應(yīng)的方法執(zhí)行即可。
String sql = "SELECT id,name FROM user WHERE name=:name AND id<:user_id";
MapSqlParameterSource namedParameters = new MapSqlParameterSource();
namedParameters.addValue("name", "test");
namedParameters.addValue("user_id", 100, Types.INTEGER);
User user = namedParameterJdbcTemplate.queryForObject(sql, namedParameters, new UserRowMapper());
System.out.println(user);
如果不想創(chuàng)建MapSqlParameterSource對象,還可以直接使用一個Map傳遞命名參數(shù)的名稱和值主经。
Map<String, Object> map = new HashMap<>();
map.put("user_id", 100);
map.put("name", "test");
List<User> users = namedParameterJdbcTemplate.query(sql, map, new UserRowMapper());
System.out.println(users);
上面討論的MapSqlParameterSource
實際上實現(xiàn)了SqlParameterSource
接口荣暮,上面的幾個方法簽名也是接受SqlParameterSource
接口。這個接口表示用來傳遞命名參數(shù)和值的集合罩驻。除了MapSqlParameterSource
之外穗酥,還有另外一個常用的實現(xiàn),BeanPropertySqlParameterSource
惠遏,這個類接受一個Java Bean對象砾跃,然后使用Bean的屬性名和值作為命名參數(shù)的名稱和值。這一點需要注意爽哎。
User bean = new User(100, "test");
SqlParameterSource parameterSource = new BeanPropertySqlParameterSource(bean);
users = namedParameterJdbcTemplate.query(sql, parameterSource, new UserRowMapper());
System.out.println(users);
使用SimpleJdbc類
前面所說的JdbcTemplate封裝了一些功能蜓席,讓我們方便的使用JDBC。Spring還提供了幾個更高級课锌、功能更具體的SimpleJdbc類厨内。這些類會讀取JDBC的元數(shù)據(jù)Metadata,使用起來更加方便渺贤。
SimpleJdbcInsert
SimpleJdbcInsert類用來插入數(shù)據(jù)雏胃。簡單的使用方法如下。SimpleJdbcInsert需要一個數(shù)據(jù)源來創(chuàng)建志鞍,withTableName方法指定要插入的表名瞭亮,usingGeneratedKeyColumns指定設(shè)置了主鍵自增的列名。其他使用方法和前面所說的類類似固棚。executeAndReturnKey這個方法很特別统翩,它會將數(shù)據(jù)插入數(shù)據(jù)庫并返回該條記錄對應(yīng)的自增鍵。有時候我們可能希望使用自增主鍵來插入一條數(shù)據(jù)此洲,由于主鍵是數(shù)據(jù)庫自動生成的厂汗,我們必須再次查詢數(shù)據(jù)庫才能獲得主鍵。這種情況下使用executeAndReturnKey非常方便呜师。注意這個方法返回的是java.lang.Number
類型娶桦,可以調(diào)用其XXXvalue
方法轉(zhuǎn)換成各種數(shù)值。
SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(dataSource)
.withTableName("user")
.usingGeneratedKeyColumns("id");
User user = new User();
user.setName("test");
Map<String, Object> params = new HashMap<>();
params.put("names", user.getName());
int id = simpleJdbcInsert.executeAndReturnKey(params).intValue();
System.out.println("simpleJdbcInsert" + user);
SimpleJdbcCall
SimpleJdbcCall類用來調(diào)用存儲過程的汁汗。使用方法類似衷畦。這里就直接給出Spring官方文檔的示例代碼了。
MySQL存儲過程知牌。
CREATE FUNCTION get_actor_name (in_id INTEGER)
RETURNS VARCHAR(200) READS SQL DATA
BEGIN
DECLARE out_name VARCHAR(200);
SELECT concat(first_name, ' ', last_name)
INTO out_name
FROM t_actor where id = in_id;
RETURN out_name;
END;
SimpleJdbcCall調(diào)用存儲過程祈争。
public class JdbcActorDao implements ActorDao {
private JdbcTemplate jdbcTemplate;
private SimpleJdbcCall funcGetActorName;
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.setResultsMapCaseInsensitive(true);
this.funcGetActorName = new SimpleJdbcCall(jdbcTemplate)
.withFunctionName("get_actor_name");
}
public String getActorName(Long id) {
SqlParameterSource in = new MapSqlParameterSource()
.addValue("in_id", id);
String name = funcGetActorName.executeFunction(String.class, in);
return name;
}
// ... additional methods
}
如果要從存儲過程獲取記錄的話,可以這樣送爸。以下是一個MySQL存儲過程暖释。
CREATE PROCEDURE read_all_actors()
BEGIN
SELECT a.id, a.first_name, a.last_name, a.birth_date FROM t_actor a;
END;
相對應(yīng)的Java代碼。
public class JdbcActorDao implements ActorDao {
private SimpleJdbcCall procReadAllActors;
public void setDataSource(DataSource dataSource) {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.setResultsMapCaseInsensitive(true);
this.procReadAllActors = new SimpleJdbcCall(jdbcTemplate)
.withProcedureName("read_all_actors")
.returningResultSet("actors",
BeanPropertyRowMapper.newInstance(Actor.class));
}
public List getActorsList() {
Map m = procReadAllActors.execute(new HashMap<String, Object>(0));
return (List) m.get("actors");
}
// ... additional methods
}
將JDBC操作轉(zhuǎn)化為Java對象
org.springframework.jdbc.object
包下提供了一組類墨吓,讓我們用更加面向?qū)ο蟮姆绞絹聿僮鲾?shù)據(jù)庫球匕。我們可以將SQL查詢轉(zhuǎn)化為一組業(yè)務(wù)對象,也可以方便的進行查詢帖烘、更新和執(zhí)行存儲過程的操作亮曹。
MappingSqlQuery
MappingSqlQuery是一個抽象類,繼承自SQLQuery秘症。我們在使用這個類的時候需要創(chuàng)建一個自定義類照卦,繼承自MappingSqlQuery,然后在其構(gòu)造方法中初始化一個查詢字符串乡摹,并在這里設(shè)置查詢參數(shù)役耕;然后需要實現(xiàn)該類的mapRow方法,將結(jié)果集的行轉(zhuǎn)化為實體類對象聪廉。下面是一個例子瞬痘。構(gòu)造方法中定義的查詢字符串會被創(chuàng)建為PreparedStatement,因此可以在查詢字符串中使用占位符?
板熊。對于每個出現(xiàn)的占位符框全,我們都必須調(diào)用declareParameter方法聲明參數(shù),該方法接受一個SqlParameter對象干签,該對象需要參數(shù)名和類型兩個參數(shù)津辩。最后需要調(diào)用compile方法編譯和準(zhǔn)備查詢。該類是線程安全的容劳,因此可以安全的在多個線程之間共享對象喘沿。
public class UserMappingSqlQuery extends MappingSqlQuery<User> {
public UserMappingSqlQuery(DataSource ds) {
super(ds, "SELECT id,name FROM user WHERE id=:id");
super.declareParameter(new SqlParameter("id", Types.INTEGER));
compile();
}
@Override
protected User mapRow(ResultSet rs, int rowNum) throws SQLException {
return new User(rs.getInt(1), rs.getString(2));
}
}
然后我們創(chuàng)建一個對象,調(diào)用findObject方法并傳入查詢參數(shù)竭贩,即可獲得結(jié)果對象摹恨。
@Test
public void testMappingSqlQuery() {
MappingSqlQuery<User> mappingSqlQuery = new UserMappingSqlQuery(dataSource);
User user = mappingSqlQuery.findObject(1);
logger.debug(user);
}
如果查詢要返回一組記錄并傳遞多個查詢參數(shù)。需要調(diào)用相應(yīng)的execute方法娶视。一下是另一個MappingSqlQuery,以及其測試代碼睁宰。
public class UsersMappingSqlQuery extends MappingSqlQuery<User> {
public UsersMappingSqlQuery(DataSource ds) {
super(ds, "SELECT id,name FROM user WHERE id<? AND name LIKE ?");
super.declareParameter(new SqlParameter("id", Types.INTEGER));
super.declareParameter(new SqlParameter("name", Types.VARCHAR));
compile();
}
@Override
protected User mapRow(ResultSet rs, int rowNum) throws SQLException {
return new User(rs.getInt(1), rs.getString(2));
}
}
//獲取多個對象
mappingSqlQuery = new UsersMappingSqlQuery(dataSource);
List<User> users = mappingSqlQuery.execute(100, "test");
logger.debug(users);
使用SqlUpdate
這個類的使用方法和SqlQuery類似肪获,但是由于它是一個具體類,因此不需要定義子類即可使用柒傻。下面是它的簡單使用方法孝赫。為了更新具體的數(shù)據(jù)(例如一個Java Bean對象),你也可以繼承該類红符,并提供自己的更新方法青柄,就和上面一樣伐债。
@Test
public void testSqlUpdate() {
SqlUpdate sqlUpdate = new SqlUpdate(dataSource, "INSERT INTO user(name) VALUES(?)");
sqlUpdate.declareParameter(new SqlParameter("name", Types.VARCHAR));
sqlUpdate.compile();
sqlUpdate.update("wang5");
List<User> users = jdbcTemplate.query("SELECT id,name FROM user", new UserRowMapper());
logger.debug(users);
}
使用StoredProcedure
StoredProcedure是關(guān)系數(shù)據(jù)庫中存儲過程概念的抽象類,提供了一組方便的受保護方法致开。因此在使用該類的時候需要我們創(chuàng)建一個子類峰锁,繼承該類。在使用這個類的時候我們需要使用setSql方法設(shè)置數(shù)據(jù)庫中存儲過程的名稱双戳。在傳遞參數(shù)的時候虹蒋,使用SqlParameter傳遞IN參數(shù),使用SqlOutParameter傳遞OUT參數(shù)飒货,使用SqlInOutParameter傳遞INOUT參數(shù)魄衅。
以下是Spring官方文檔的一個例子。
class GetSysdateProcedure extends StoredProcedure {
private static final String SQL = "sysdate";
public GetSysdateProcedure(DataSource dataSource) {
setDataSource(dataSource);
setFunction(true);
setSql(SQL);
declareParameter(new SqlOutParameter("date", Types.DATE));
compile();
}
public Date execute() {
// the 'sysdate' sproc has no input parameters, so an empty Map is supplied...
Map<String, Object> results = execute(new HashMap<String, Object>());
Date sysdate = (Date) results.get("date");
return sysdate;
}
}
其他知識
提供SQL參數(shù)信息
一般情況下Spring可以自行決定SQL參數(shù)的類型塘辅,但是有時候或者說最好由我們提供準(zhǔn)確的SQL參數(shù)信息晃虫。
-
JdbcTemplate
的很多查詢和更新方法包含一個額外的參數(shù),一個int數(shù)組扣墩,該數(shù)組應(yīng)該是java.sql.Types
指定的一些常量哲银,表明SQL參數(shù)的類型。 - 可以使用
SqlParameterValue
來設(shè)置參數(shù)的值沮榜,在創(chuàng)建該對象的時候提供參數(shù)的值和類型盘榨。 - 如果使用具有命名參數(shù)功能的類時,使用
SqlParameterSource
類(BeanPropertySqlParameterSource
或MapSqlParameterSource
)來指定命名參數(shù)和其類型蟆融。
數(shù)據(jù)源
我們在學(xué)習(xí)JDBC的時候草巡,基本上都是從DriverManager類創(chuàng)建一個數(shù)據(jù)庫連接。在實際環(huán)境中型酥,我們應(yīng)該使用數(shù)據(jù)源(DataSource)來創(chuàng)建數(shù)據(jù)庫連接山憨。數(shù)據(jù)源將創(chuàng)建數(shù)據(jù)庫的職責(zé)和應(yīng)用代碼分離,數(shù)據(jù)源可以交給數(shù)據(jù)庫管理員來設(shè)置弥喉,程序員只需要獲取數(shù)據(jù)源對象郁竟,然后開發(fā)相關(guān)代碼。
在上面的例子中我們使用的是Apache的commons-dbcp2
數(shù)據(jù)源由境,Spring自己也實現(xiàn)了幾個數(shù)據(jù)源方便我們開發(fā)和測試棚亩。
DriverManagerDataSource
是一個簡單的數(shù)據(jù)源,每次請求都會返回一個新的數(shù)據(jù)庫連接虏杰。它使用數(shù)據(jù)庫驅(qū)動來創(chuàng)建數(shù)據(jù)源讥蟆,就像我們使用DriverManager
那樣。這是一個簡單的測試類纺阔,可以幫助我們在不借助任何Java EE容器的情況下獲取數(shù)據(jù)源瘸彤。但是由于使用commons-dbcp2
這樣的成熟數(shù)據(jù)源也很容易,所以其實我們只需要使用commons-dbcp2
即可笛钝。
SingleConnectionDataSource
也是一個數(shù)據(jù)源质况,它包裝了一個單獨的數(shù)據(jù)庫連接愕宋,在每次請求都會返回同一個數(shù)據(jù)庫連接對象。和DriverManagerDataSource
相比它更輕量结榄,因為沒有創(chuàng)建額外數(shù)據(jù)庫連接的開銷中贝。
初始化數(shù)據(jù)源
在創(chuàng)建數(shù)據(jù)源的時候我們可以在Spring配置文件中設(shè)置數(shù)據(jù)源的初始化腳本。
<jdbc:initialize-database data-source="dataSource">
<jdbc:script location="classpath:com/foo/sql/db-schema.sql"/>
<jdbc:script location="classpath:com/foo/sql/db-test-data.sql"/>
</jdbc:initialize-database>
有時候我們希望在初始化數(shù)據(jù)的時候刪除上一次的測試數(shù)據(jù)潭陪。但是如果數(shù)據(jù)庫不支持類似DROP TABLE IF EXISTS
這樣的語法雄妥,那么我們就必須在初始化腳本中添加一些DROP
語句。這些刪除語句可能會失斠浪荨(如果沒有測試數(shù)據(jù)的情況下執(zhí)行刪除)老厌,這時候就可以忽略刪除失敗。當(dāng)初始化腳本出現(xiàn)錯誤的時候就會拋出異常黎炉,但是如果設(shè)置了忽略刪除失敗枝秤,Spring就會直接忽略這些失敗而不拋出異常。ignore-failures屬性還可以取另外兩個值NONE
和ALL
慷嗜,分別表示不忽略失敗和忽略所有失敗淀弹。
<jdbc:initialize-database data-source="dataSource" ignore-failures="DROPS">
<jdbc:script location="..."/>
</jdbc:initialize-database>
我們還可以設(shè)置初始化腳本的間隔符。
<jdbc:initialize-database data-source="dataSource" separator="@@">
<jdbc:script location="classpath:com/foo/sql/db-schema.sql" separator=";"/>
<jdbc:script location="classpath:com/foo/sql/db-test-data-1.sql"/>
<jdbc:script location="classpath:com/foo/sql/db-test-data-2.sql"/>
</jdbc:initialize-database>
工具類
org.springframework.jdbc.datasource.DataSourceUtils
庆械,這是一個方便的工具類薇溃,包含了一組和數(shù)據(jù)源相關(guān)的工具方法。
org.springframework.jdbc.support.JdbcUtils
類提供了一些方法來操作JDBC缭乘,在Spring內(nèi)部使用沐序,也可以用于自己的JDBC操作。
還有幾個工具類主要由Spring內(nèi)部使用堕绩,這里就不列舉了策幼。
嵌入式數(shù)據(jù)庫支持
我們在開發(fā)數(shù)據(jù)庫應(yīng)用的時候需要安裝某種類型的數(shù)據(jù)庫,比如MySQL等等奴紧。但是這樣就需要額外的項目依賴特姐。這樣一個產(chǎn)品級的數(shù)據(jù)庫軟件動輒上G,安裝黍氮、測試都不方便唐含。這時候我們可以使用嵌入式數(shù)據(jù)庫進行開發(fā)和測試。嵌入式數(shù)據(jù)庫具有占用小沫浆、啟動快觉壶、配置簡單等特點,非常適合開發(fā)測試件缸。而且由于嵌入式數(shù)據(jù)庫系統(tǒng)占用低,在一些設(shè)備上還可以直接作為存儲數(shù)據(jù)庫使用叔遂。例如輕量級嵌入式數(shù)據(jù)庫Sqlite他炊,就安裝在每個安卓手機中争剿,用于存儲數(shù)據(jù)。
在Spring中創(chuàng)建一個嵌入式數(shù)據(jù)庫痊末,在XML中添加如下一段蚕苇。這樣創(chuàng)建出來的數(shù)據(jù)庫可以直接作為javax.sql.DataSource
類型的Spring Bean使用。最好設(shè)置generate-name="true"
生成一個唯一名稱凿叠。默認(rèn)情況下創(chuàng)建的是HSQL嵌入式數(shù)據(jù)庫涩笤。當(dāng)然別忘了添加相應(yīng)嵌入式數(shù)據(jù)庫的依賴項。
<jdbc:embedded-database id="dataSource" generate-name="true">
<jdbc:script location="classpath:schema.sql"/>
<jdbc:script location="classpath:test-data.sql"/>
</jdbc:embedded-database>
當(dāng)然還可以以編程方式創(chuàng)建嵌入式數(shù)據(jù)庫盒件。下面是上面等價的編程方式蹬碧。
@Configuration
public class DataSourceConfig {
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.generateUniqueName(true)
.setType(H2)
.setScriptEncoding("UTF-8")
.ignoreFailedDrops(true)
.addScript("schema.sql")
.addScripts("user_data.sql", "country_data.sql")
.build();
}
}
除了HSQL,Spring還支持H2和Derby兩種嵌入式數(shù)據(jù)庫(值得一提的是炒刁,現(xiàn)在的JDK分發(fā)包中附帶了一個Java DB數(shù)據(jù)庫恩沽,在安裝了JDK之后可以在JDK安裝目錄中看到db文件夾,這里面存放的其實就是Derby數(shù)據(jù)庫)翔始。要指定數(shù)據(jù)庫類型罗心,在上面的XML片段中添加embedded-database
屬性并設(shè)置HSQL
、H2
或Derby
城瞎。如果使用編程方式渤闷,在EmbeddedDatabaseBuilder
上調(diào)用setType(EmbeddedDatabaseType)
方法,該方法的參數(shù)指定一個枚舉脖镀,指定這三種類型飒箭。
上面的generate-name="true"
或者generateUniqueName(true)
挺重要的。如果不指定這個屬性认然。在多次調(diào)用嵌入式數(shù)據(jù)庫之后补憾,可能會生成多個數(shù)據(jù)庫實例。為了避免這種情況發(fā)生卷员,需要設(shè)置這個屬性盈匾。設(shè)置之后,如果已經(jīng)存在了數(shù)據(jù)庫實例毕骡,就會使用這個已存在的實例削饵,而不是設(shè)置新的實例。這個屬性是在Spring 4.2中增加的未巫。使用以下幾個方法都可以設(shè)置該屬性窿撬。
EmbeddedDatabaseFactory.setGenerateUniqueDatabaseName()
EmbeddedDatabaseBuilder.generateUniqueName()
<jdbc:embedded-database generate-name="true" …? >
參考資料
http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#jdbc
項目代碼在Csdn代碼庫,有興趣的同學(xué)可以看看叙凡。
最后祝大家新年快樂劈伴!