osgi实战项目(osmp)一步一步玩转osgi之jdbc(6)

    已经有很长一段时间没有更新了,年底了比较忙,最近很多新加入的朋友在问jdbc这段,今天抽点空讲一下osmp-jdbc的封装。

 

    osmp的jdbc相比其它框架的来讲主要有以下几点不同。

 

  • 基于druid的多数据源管理
  • 支持多种类型的数据库,目前支持mysql,oracle,mssql。
  • 提供数据源动态创建和消毁
  • 提供基于动态sql管理和解析
  • 提供类似于mybaties的springTemplate的dao封装

   最开始的时候我的想法很简单,给我一个数据库链接,给我一个sql语句,我就能给你想要的数据,结合osgi的动态性来实现。

 

先从动态数据源来说,从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语句监控,数据源管理,数据源监控。

 

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 服务,这里不作详细介绍 ,有兴趣的同学自己百度吧。

 

 

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以后才提供的功能。

 

有了数据源后,我们更进一步的将数据源与springTemplate结合,通过JdbcTemplateManager来管理模板,通过 JdbcTemplateManager 的 addDataSource方法,根据数据库类型实例化不同数据库的模板并添加到JdbcTemplateManager里。

 

com.osmp.jdbc.service.JdbcTemplateManager

 

//添加数据源信息
    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操作,方便业务开发直接调用。

 

现在我们只需要一个数据源的标识加一句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开发一个用户的增删改查。

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值