已經有很長一段時間沒有更新了,年末了比較忙,最近不少新加入的朋友在問jdbc這段,今天抽點空講一下osmp-jdbc的封裝。java
osmp的jdbc相比其它框架的來說主要有如下幾點不一樣。mysql
- 基於druid的多數據源管理
- 支持多種類型的數據庫,目前支持mysql,oracle,mssql。
- 提供數據源動態建立和消毀
- 提供基於動態sql管理和解析
- 提供相似於mybaties的springTemplate的dao封裝
最開始的時候個人想法很簡單,給我一個數據庫連接,給我一個sql語句,我就能給你想要的數據,結合osgi的動態性來實現。spring
先從動態數據源來講,從resources/META-INF/spring/jdbc-context.xml 配置文件當中咱們能夠看到,spring配置文件加載後,咱們實例化了 com.osmp.jdbc.service.SqlStatementManager, com.osmp.jdbc.service.SqlStatementMonitor, com.osmp.jdbc.service.DataSourceManager, com.osmp.jdbc.service.DataSourceMonitor這四個類,分別爲sql語句管理,sql語句監控,數據源管理,數據源監控。sql
DataSourceMonitor(數據源監控)實現spring 的 InitializingBean和 DisposableBean接口,實例化傳入了數據源配置目錄和數據源管理兩個參數,bean初始時經過傳入的數據源配置目錄獲取全部配置並解析後實例化DruidDataSource 添加到DataSourceManager中。 同時啓了一個線程監控數據源配置目錄,若是一旦有新增的配置後解析並添加到數據源管理裏。代碼以下數據庫
@Override public void afterPropertiesSet() throws Exception { Assert.notNull(dataSourceDir, "dataSource文件目錄不能爲空..."); Assert.notNull(dataSourceManager, "dataSourceManager未初始化..."); final File resFile = new File(dataSourceDir); Assert.isTrue(resFile.exists(), "dataSource文件目錄不存在..."); filepath2datasourceNameMap.clear(); for(File file : resFile.listFiles()){ addDataSource(file.getName()); } new Thread(){ public void run(){ try { monitor(resFile); } catch (Exception e) { e.printStackTrace(); } } }.start(); }
文件監控使用的是jdk1.7的 WatchService 服務,這裏不做詳細介紹 ,有興趣的同窗本身百度吧。oracle
private void monitor(File file) throws Exception{ watchService = FileSystems.getDefault().newWatchService(); file.toPath().register(watchService, StandardWatchEventKinds.ENTRY_CREATE,StandardWatchEventKinds.ENTRY_DELETE); while(running){ WatchKey watchKey = watchService.take(); List<WatchEvent<?>> events = watchKey.pollEvents(); if(events != null){ for(WatchEvent<?> e : events){ //事件處理 final WatchEvent<Path> watchEventPath = (WatchEvent<Path>)e; final Path filename = watchEventPath.context(); if(e.kind() == StandardWatchEventKinds.ENTRY_CREATE){ addDataSource(filename.toString()); }else if(e.kind() == StandardWatchEventKinds.ENTRY_DELETE){ removeDataSource(filename.toString()); } } } if(!watchKey.reset()){ watchKey.cancel(); logger.error("移除dataSource文件目錄監控服務"); break; } } running = false; watchService.close(); }
只要數據源配置目錄一旦有文件添加、刪除、修改事件發生,都會進行相應的處理,新增、刪除、修改數據源,這也是動態數據源的核心部分,我相信同窗們看了後,在之後的項目當中也可使用 WatchService 服務實現更多動態功能吧。切記WatchService 服務是 JDK1.7之後才提供的功能。app
有了數據源後,咱們更進一步的將數據源與springTemplate結合,經過JdbcTemplateManager來管理模板,經過 JdbcTemplateManager 的 addDataSource方法,根據數據庫類型實例化不一樣數據庫的模板並添加到JdbcTemplateManager裏。框架
com.osmp.jdbc.service.JdbcTemplateManageride
//添加數據源信息 public void addDataSource(DataSource ds,String catalog,DBType dbType){ if(ds == null || catalog == null || dbType == null) return; BaseTemplate jdbcTemplate = null; if(dbType.equals(DBType.SQLSERVER)){ jdbcTemplate = new MSSQLTemplate(); }else if(dbType.equals(DBType.MYSQL)){ jdbcTemplate = new MysqlTemplate(); }else{ jdbcTemplate = new OracleTemplate(); } jdbcTemplate.setOwnJdbcTemplate(new NamedParameterJdbcTemplate(ds)); jdbcTemplate.setTransactionManager(new DataSourceTransactionManager(ds)); //dsTransactionManager.setGlobalRollbackOnParticipationFailure(false); //指定主事務決定回滾 templates.put(catalog.toUpperCase(), jdbcTemplate); }
com.osmp.jdbc.support.JdbcTemplate 封裝了大量的C,R,U,D操做,方便業務開發直接調用。ui
如今咱們只須要一個數據源的標識加一句sql,咱們就能夠執行C,R,U,D操做了。
上面咱們介紹了動態數據源這部分,下面咱們該聊一聊動態sql了。我大概記得當時我是想直接在osgi環境下集成mybaties來着,好像研究了兩週最後我放棄了,基於mybaties的開發習慣,本身寫了一套相似於東東,有點兒重複造輪子吧。
其實實現也很簡單:
sql配置文件 + 一個sql配置文件解析器 + 一個RowMapper實現類
首先咱們定義了一個dtd文件用以限定sql 配置文件。
咱們經過動態數據的方式,SqlStatementMonitor監聽一個目錄做爲sql腳本xml的目錄。當有sql配置腳本xml添加的時候就解析xml文件並保存到SqlStatmentManager裏。
一旦有新的sql配置xml被添加後,就會進入SqlStatementMonitor.SqlUpdateTask.run() 方法被解析後加載到SqlStatementManager 裏。
//sql文件更新任務 private class SqlUpdateTask implements Runnable { private File file; private boolean isDelete; public SqlUpdateTask(File file,boolean isDelete){ this.file = file; this.isDelete = isDelete; } public void run() { if(file == null) return; String filename = file.getAbsolutePath(); if(!filename.endsWith(".xml")){ return; } sqlStatementManager.removeSqls(filename); if(isDelete) return; sqlStatementManager.putSql(filename, SqlParserUtils.parse(file)); } }
SQL配置是類mybaties的配置。最開始想直接mybaties的解析部分,看了一下很難,還不如本身寫了,因此基本上myabties支持的。osmp也基本支持,甚至支持更多的高級特性,好比include advanced等,有待同窗們本身發掘,當時你也能夠本身擴充。這部有興趣的同窗能夠重構,將數據源與sql解析剝離出來。
osmp同時提供 JdbcDao封裝,只須要sql配置xml裏的 id + 數據源名稱就能夠返回數據了。這也對應上面提到的需求,給一個sql + 數據源連接 我返給你結果。。。
隨便提一下。對於實體bean 和 ResultSet之間的轉換是經過定義 Column註解來進行的。獲取數據的時候 須要傳入一個 實體.class 經過反射解析@Column 從 ResultSet裏獲取數據 詳見 com.osmp.jdbc.define.tool.ToolsRowMapper
最後看一下 sql xml的定義例子
<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE sqls SYSTEM "osmp_sql.dtd"> <sqls> <select id="demo.queryuser"> select * from demo_user <where> <if test="name not empty"> and name=:name </if> <if test="age not empty"> and age=:age </if> </where> </select> <insert id="demo.adduser"> insert into demo_user(id,name,age,remark) values(:id,:name,:age,:remark) </insert> <delete id="demo.deluser"> delete demo_user where id=:id </delete> <update id="demo.upuser"> update demo_user set <if test="name not empty"> name = :name </if> <if test="age not empty"> name = :age </if> <if test="remark not empty"> remark = :remark </if> <where> id = :id </where> </update> <select id="demo.choose.when"> select x,y,z from xxx WITH ( NOLOCK ) where x in ( select x,y,z from yyy with(nolock) where ISNULL(x, '') != '' <choose> <when test="acctype == 0"><![CDATA[ and x=:x ]]></when> <when test="acctype == 1">and y=:y</when> </choose> ) </select> </sqls>
sql更多高級動態特性還有待朋友們本身去發掘,咱們開發的時候只須要將 此sql的配置xml和 數據源的properties配置 分別放到 ${servicemix_home}/etc/sqls 和 ${servicemix_home}/etc/datasources 目錄下,就會被動態解析保存和動態建立數據源。
最後一步,咱們將JdbcFinderManager發佈爲一個osgi的服務供其它的bundle調用。
resource/META-INF/spring/jdbc-context.xml
<osgi:service interface="com.osmp.jdbc.support.JdbcFinderManager" ref="osmp.JdbcFinderManager"> </osgi:service>
接下來咱們只須要寫一個簡單的demo調用他們就好了。
下一講咱們實戰講解怎麼demo開發一個用戶的增刪改查。