Esper学习之十:EPL语法(六)

在esper的文档中,epl访问数据库的配置放在了比较靠后的位置,不过为了方便各位学习,这里会先说明和数据库交互的相关配置,然后再说epl怎么访问数据库。

配置文件在官方esper包的etc文件夹下,大家可以参考着学习。

1.连接数据库

a.JNDI获取连接

配置如下:

[html] view plaincopy

  1. <database-reference name="mydb1">
  2. <datasource-connection context-lookup-name="java:comp/env/jdbc/mydb">
  3. <env-property name="java.naming.factory.initial" value ="com.myclass.CtxFactory"/>
  4. <env-property name="java.naming.provider.url" value ="iiop://localhost:1050"/ >
  5. </datasource-connection>
  6. </database-reference>

database-reference的name是要连接的数据库名字,其余的配置可参考JNDI的文档

使用方法:

[java] view plaincopy

  1. if (envProperties.size() > 0) {
  2. initialContext = new InitialContext(envProperties);
  3. } else {
  4. initialContext = new InitialContext();
  5. }
  6. DataSource dataSource = (DataSource) initialContext.lookup(lookupName);
  7. Connection connection = dataSource.getConnection();

更多内容可参考JNDI的文档

b.从连接池获取连接

配置如下:(以dbcp为例)

[html] view plaincopy

  1. <database-reference name="mydb3">
  2. <!-- For a complete list of properties see Apache DBCP. -->
  3. <datasourcefactory-connection class-name="org.apache.commons.dbcp.BasicDataSourceFactory">
  4. <env-property name="username" value ="myusername"/>
  5. <env-property name="password" value ="mypassword"/>
  6. <env-property name="driverClassName" value ="com.mysql.jdbc.Driver"/>
  7. <env-property name="url" value ="jdbc:mysql://localhost/test"/>
  8. <env-property name="initialSize" value ="2"/>
  9. <env-property name="validationQuery" value ="select 1 from dual"/>
  10. </datasourcefactory-connection>
  11. <connection-lifecycle value="pooled"/>





</database-reference>


相同的配置可以使用esper的api达到同样的效果。代码如下:

[java] view plaincopy

  1. Properties props = new Properties();
  2. props.put("username", "myusername");
  3. props.put("password", "mypassword");
  4. props.put("driverClassName", "com.mysql.jdbc.Driver");
  5. props.put("url", "jdbc:mysql://localhost/test");
  6. props.put("initialSize", 2);
  7. props.put("validationQuery", "select 1 from dual");
  8. ConfigurationDBRef configDB = new ConfigurationDBRef();
  9. // BasicDataSourceFactory is an Apache DBCP import
  10. configDB.setDataSourceFactory(props, BasicDataSourceFactory.class.getName());
  11. configDB.setConnectionLifecycleEnum(ConfigurationDBRef.ConnectionLifecycleEnum.POOLED);
  12. Configuration configuration = new Configuration();
  13. configuration.addDatabaseReference("mydb3", configDB);

同样,也可以自己实现数据源。示例如下:

[java] view plaincopy

  1. configDB.setDataSourceFactory(props, MyOwnDataSourceFactory.class.getName());
  2. ...
  3. class MyOwnDataSourceFactory {
  4. public static DataSource createDataSource(Properties properties) {
  5. return new MyDataSourceImpl(properties);
  6. }
  7. }

c.JDBC获取连接

前提是要将对应的jdbc驱动假如classpath

[html] view plaincopy

  1. <database-reference name="mydb2">
  2. <drivermanager-connection class-name="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/mydb2" user="myuser" password="mypassword">
  3. <connection-arg name="user" value ="myuser"/>
  4. <connection-arg name="password" value ="mypassword"/>
  5. <connection-arg name="somearg" value ="someargvalue"/>
  6. </drivermanager-connection>
  7. </database-reference>

注意:drivermanager-connection中的user和password属性必须填写,即使增加了connection-arg参数也不行。所以实际上connection-arg的user和password是不需要写的。这点我觉得esper做的不够人性化。

d.其他关于数据库连接的配置

下面是一些和数据库交互的配置,更多配置可参考Javadoc

[html] view plaincopy

  1. <database-reference name="mydb2">
  2. ... configure data source or driver manager settings...
  3. <connection-settings auto-commit="true" catalog="mycatalog" read-only="true" transaction-isolation="1" />
  4. </database-reference>

下面是关于连接的生命周期的配置

[html] view plaincopy

  1. <database-reference name="mydb2">
  2. ... configure data source or driver manager settings...
  3. <connection-lifecycle value="pooled"/><!-- retain -->
  4. </database-reference>

如果参数值为pooled,当配置了连接池,则会将每次获取的连接还给连接池。若没配置连接池,则每次获取的连接用完后就关闭。

如果参数值为retain,则会将连接缓存到esper引擎中,这个epl用完后,另一个epl可以接着用

2.查询结果缓存策略
EPL和数据库交互时会产生查询结果,所以引擎若能缓存查询结果将大大提高执行效率,因此esper提供了两种缓存模式。

a.LRU Cache
LRU即least-recently-used,中文释义为“最近最少使用”,学过OS的应该知道内存缓存策略里也有这个算法,不明白的请自行搜索。配置如下:

[html] view plaincopy

  1. <database-reference name="mydb">
  2. ... configure data source or driver manager settings...
  3. <lru-cache size="1000"/>
  4. </database-reference>

size的参数值表示最多能缓存多少条查询结果,而不是大小

b.Expiry-time Cache
该策略为每一次的查询结果设置了存活期(注意不是每一条查询结果),并且定期清理过期的查询结果。配置如下:

[html] view plaincopy

  1. <database-reference name="mydb">
  2. ... configure data source or driver manager settings...
  3. <expiry-time-cache max-age-seconds="60" purge-interval-seconds="120" ref-type="soft"/>
  4. </database-reference>

max-age-seconds表示存活时间,purge-interval-seconds表示每隔多久清理一次过期的内容,两者单位都是秒。
ref-type有三个参数值:weak,soft,hard。表示查询结果的引用级别,JVM垃圾回收的时候,会根据此参数决定何时释放缓存。具体解释如下:
1).weak表示弱引用,JVM在垃圾回收的时候将清除所有的缓存,释放内存。
2).soft表示软引用,JVM在垃圾回收的时候,只有当所有的弱引用都被回收了才会清除所有的缓存并释放空间。
3).hard表示强引用,JVM的垃圾回收不会清除缓存,所以引擎将按照规定的存活期和清理时间管理缓存。

3.Column Change Case
通常情况下,表字段是大小写不敏感的,但是也有设置为小写敏感的情况,我们可以通过设置使得查询返回的列结果为大写或者小写。配置如下:

[html] view plaincopy

  1. <column-change-case value="lowercase"/>

4.SQL Types Mapping
默认的数据库字段类型映射可以满足需求,不过想修改也是可以的。配置如下:

[html] view plaincopy

  1. <sql-types-mapping sql-type="2" java-type="int" />

sql-type表示数据库字段类型,这里的2映射了具体类型,可在java.sql.Types类中查到,并且这个类里包含了大部分的数据库字段类型。java-type表示对应的java数据类型,大小写不敏感。

以上就是EPL和数据库交互的相关配置,下面来讲解EPL是怎么和数据库交互的。

EPL和数据库交互有两个前提,一是JDBC驱动能够预编译sql,而是JDBC驱动能获取数据库的元数据。

5.Joining SQL Query Results
通常我们想要的一种交互方式是:输入某个事件到引擎,然后引擎把事件的某个属性作为sql的查询条件交给JDBC驱动,执行sql。正好esper为此提供了相应的解决办法,参看语法:

[plain] view plaincopy

  1. sql:database_name [" parameterized_sql_query "]

sql是关键字不可少,parameterized_sql_query为sql语句,只与具体的DB有关,无关esper,所以数据库的那些个函数都可以用。先看一个简单的例子:

[plain] view plaincopy

  1. select custId, cust_name from CustomerCallEvent, sql:MyCustomerDB [‘ select cust_name from Customer where cust_id = ${custId} ‘]

引擎接收CustomerCallEvent事件,将事件的custId属性作为查询值,执行MyCustomerDB数据库的Customer表,其中查询条件为Customer的cust_id字段值存在,然后返回相应的custId属性值和cust_name字段值给监听器

该语法有几点需要注意:
a.sql需要用单引号或者双引号引起来,然后再用方括号括起来。
b.${expression}中可以是事件属性,可以是变量、常量等,也可以是用户自定义的函数。例如:

[plain] view plaincopy

  1. select * from LimitEvent le,
  2. sql:MyCustomerDB [‘ select cust_name from Customer where
  3. amount > ${max(varLowerLimit, MyLib.getLimit(le))} ‘]

c.join的事件可以使用view,但是sql不可使用。不过可以将sql的查询结果通过insert into输出到另外的事件,然后再使用view。例如:

[plain] view plaincopy

  1. select customerId, customerName from CustomerCallEvent.win:time(30 sec) as cce,
  2. sql:MyCustomerDB ["select cust_id as customerId, cust_name as customerName
  3. from Customer
  4. where cust_id = ${cce.custId}"] as cq

d.可以用as为表的字段设置别名,例如:

[plain] view plaincopy

  1. select custId, custName from CustomerCallEvent, sql:MyCustomerDB [‘ select cust_name as custName from Customer where cust_id = ${custId} ‘]

e.当使用事件的属性作为查询值是,属性名不要和字段名重名,否则会报错,esper无法识别
f.join的sql语句没有限制,并且可以使用where子句。例如:

[plain] view plaincopy

  1. select symbol, symbolDesc from OrderEvent as orders,
  2. sql:My_Oracle_DB [‘select symbolDesc from SymbolReference‘] as reference,
  3. sql:My_MySQL_DB [‘select orderList from orderHistory‘] as history
  4. where reference.symbol = orders.symbol
  5. and history.symbol = orders.symbol

除了普通的join,EPL也支持outer join sql语句,语法也没有什么改变。例如:

[plain] view plaincopy

  1. select custId, custName from
  2. CustomerCallEvent as cce
  3. left outer join
  4. sql:MyCustomerDB ["select cust_id, cust_name as custName from Customer where cust_id = ${cce.custId}"] as cq
  5. on cce.custId = cq.cust_id

6.Using Patterns to Request Data
除了通过传递外部数据查询数据库,也可以用pattern定时或者以固定频率查询数据库。例如:

[plain] view plaincopy

  1. insert into NewOrders
  2. select orderId, orderAmount from
  3. pattern [every timer:interval(5 sec)],
  4. sql:MyCustomerDB [‘select orderId, orderAmount from NewOrders‘]

pattern语法之后再说,这里只让大家知道有这么一个用法。

7.Polling SQL Queries via API
Esper提供了API直接执行EPL来达到访问数据库的目的。请看下面的代码:

[java] view plaincopy

  1. package example;
  2. import com.espertech.esper.client.Configuration;
  3. import com.espertech.esper.client.EPAdministrator;
  4. import com.espertech.esper.client.EPRuntime;
  5. import com.espertech.esper.client.EPServiceProvider;
  6. import com.espertech.esper.client.EPServiceProviderManager;
  7. import com.espertech.esper.client.EPStatement;
  8. import com.espertech.esper.client.EventBean;
  9. import java.util.Iterator;
  10. /**
  11. * Created by Luonanqin on 4/17/14.
  12. */
  13. public class IteratorSQLTest {
  14. public static void main(String[] args) throws InterruptedException {
  15. Configuration config = new Configuration();
  16. config.configure("esper.examples.cfg.xml");
  17. config.addVariable("vari", Integer.class, 1);
  18. EPServiceProvider epService = EPServiceProviderManager.getDefaultProvider(config);
  19. EPAdministrator admin = epService.getEPAdministrator();
  20. EPRuntime runtime = epService.getEPRuntime();
  21. // id=1, name="luonq"
  22. String epl1 = "select id, name from sql:test[‘select id, name from test1 where id=${vari}‘]";
  23. EPStatement state = admin.createEPL(epl1);
  24. Iterator<EventBean> iter = state.iterator(); // 也可以调用safeIterator方法,该方法以线程安全方式查询DB
  25. while (iter.hasNext()) {
  26. EventBean eventBean = iter.next();
  27. System.out.println(eventBean.get("id") + " " + eventBean.get("name"));
  28. }
  29. }
  30. }

执行结果:

[plain] view plaincopy

  1. 1 luonq

8.SQL Input Parameter and Column Output Conversion
刚才数据库配置里面有说到可以修改数据库字段类型和java数据类型的映射关系,但是那只是针对全局的设置,如果想针对EPL来设置映射关系,可以实现SQLColumnTypeConversion接口,然后通过注解Hook调用实现类。具体代码及解释如下:

[java] view plaincopy

  1. import com.espertech.esper.client.hook.SQLColumnTypeContext;
  2. import com.espertech.esper.client.hook.SQLColumnTypeConversion;
  3. import com.espertech.esper.client.hook.SQLColumnValueContext;
  4. import com.espertech.esper.client.hook.SQLInputParameterContext;
  5. /**
  6. *
  7. * MySQLColumnTypeConvertor必须为public类,不然无法实例化。
  8. * Esper会为每一个EPL实例,即EPStatement提供一个Convertor实例
  9. *
  10. * 该例子没有做任何转换。
  11. * Created by Luonanqin on 2/9/14.
  12. */
  13. public class MySQLColumnTypeConvertor implements SQLColumnTypeConversion{
  14. // 转换列的类型
  15. public Class getColumnType(SQLColumnTypeContext context) {
  16. Class clazz = context.getColumnClassType();
  17. return clazz;
  18. }
  19. // 转换列的值
  20. public Object getColumnValue(SQLColumnValueContext context) {
  21. Object obj = context.getColumnValue();
  22. return obj;
  23. }
  24. // 转换传入的参数值
  25. public Object getParameterValue(SQLInputParameterContext context) {
  26. Object obj = context.getParameterValue();
  27. return obj;
  28. }
  29. }
  30. package example;
  31. import com.espertech.esper.client.Configuration;
  32. import com.espertech.esper.client.EPAdministrator;
  33. import com.espertech.esper.client.EPServiceProvider;
  34. import com.espertech.esper.client.EPServiceProviderManager;
  35. import com.espertech.esper.client.EPStatement;
  36. import com.espertech.esper.client.EventBean;
  37. import java.util.Iterator;
  38. /**
  39. * MySQLColumnTypeConvertor必须为public类,不然无法实例化。 Esper会为每一个EPL提供一个Convertor实例
  40. *
  41. * Created by Luonanqin on 2/9/14.
  42. */
  43. public class SQLColumnTypeConversionTest {
  44. public static void main(String[] args) throws InterruptedException {
  45. Configuration config = new Configuration();
  46. config.configure("esper.examples.cfg.xml");
  47. config.addVariable("vari", Integer.class, 1);
  48. EPServiceProvider epService = EPServiceProviderManager.getDefaultProvider(config);
  49. EPAdministrator admin = epService.getEPAdministrator();
  50. // id=1, name="luonq"
  51. String epl1 = "@Hook(type=HookType.SQLCOL, hook=‘" + MySQLColumnTypeConvertor.class.getName()
  52. + "‘)select id, name from sql:test[‘select id, name from test1 where id=${vari}‘]";
  53. System.out.println(epl1);
  54. EPStatement state1 = admin.createEPL(epl1);
  55. Iterator<EventBean> iter = state1.iterator();
  56. while (iter.hasNext()) {
  57. EventBean eventBean = iter.next();
  58. System.out.println(eventBean.get("id") + " " + eventBean.get("name"));
  59. }
  60. }
  61. }

执行结果:

[plain] view plaincopy

  1. @Hook(type=HookType.SQLCOL, hook=‘example.MySQLColumnTypeConvertor‘)select id, name from sql:test[‘select id, name from test1 where id=${vari}‘]
  2. 1 luonq

9.SQL Row POJO Conversion
刚才说的列类型的转换以及列结果的转换,只是普通的转换。Esper还支持表的查询结果按行转换,比如说转换为POJO,而不像之前那样只能针对每一个字段结果单独进行转换。用法也是通过Hook注解来调用转换类。代码如下:

[java] view plaincopy

  1. import java.sql.ResultSet;
  2. import java.sql.SQLException;
  3. import com.espertech.esper.client.hook.SQLOutputRowConversion;
  4. import com.espertech.esper.client.hook.SQLOutputRowTypeContext;
  5. import com.espertech.esper.client.hook.SQLOutputRowValueContext;
  6. /**
  7. * Created by Luonanqin on 2/10/14.
  8. */
  9. public class MySQLOutputRowConvertor implements SQLOutputRowConversion {
  10. // 每行查询结果转换后的类型
  11. public Class getOutputRowType(SQLOutputRowTypeContext context) {
  12. return String.class;
  13. }
  14. // 返回转换后的内容
  15. public Object getOutputRow(SQLOutputRowValueContext context) {
  16. ResultSet result = context.getResultSet();
  17. Object obj1 = null;
  18. Object obj2 = null;
  19. try {
  20. obj1 = result.getObject("id");
  21. obj2 = result.getObject("name");
  22. } catch (SQLException e) {
  23. e.printStackTrace();
  24. }
  25. return obj1 + " and " + obj2;
  26. }
  27. }
  28. package example;
  29. import com.espertech.esper.client.Configuration;
  30. import com.espertech.esper.client.EPAdministrator;
  31. import com.espertech.esper.client.EPServiceProvider;
  32. import com.espertech.esper.client.EPServiceProviderManager;
  33. import com.espertech.esper.client.EPStatement;
  34. import com.espertech.esper.client.EventBean;
  35. import java.util.Iterator;
  36. /**
  37. * MySQLOutputRowConvertovr必须为public类,不然无法实例化。 Esper会为每一个EPL提供一个Convertor实例
  38. *
  39. * Created by Luonanqin on 2/9/14.
  40. */
  41. public class SQLOutputRowConversionTest {
  42. public static void main(String[] args) throws InterruptedException {
  43. Configuration config = new Configuration();
  44. config.configure("esper.examples.cfg.xml");
  45. config.addVariable("vari", Integer.class, 1);
  46. EPServiceProvider epService = EPServiceProviderManager.getDefaultProvider(config);
  47. EPAdministrator admin = epService.getEPAdministrator();
  48. // epl中返回的流必须用“*”表示,不能是之前那样写成id或者name
  49. // id=1, name="luonq"
  50. String epl1 = "@Hook(type=HookType.SQLROW, hook=‘" + MySQLOutputRowConvertor.class.getName()
  51. + "‘)select * from sql:test[‘select id, name from test1 where id=${vari}‘]";
  52. System.out.println(epl1);
  53. EPStatement state1 = admin.createEPL(epl1);
  54. Iterator<EventBean> iter = state1.iterator();
  55. while (iter.hasNext()) {
  56. EventBean eventBean = iter.next();
  57. System.out.println(eventBean.getUnderlying());
  58. }
  59. }
  60. }

执行结果:

[plain] view plaincopy

  1. @Hook(type=HookType.SQLROW, hook=‘example.MySQLOutputRowConvertor‘)select * from sql:test[‘select id, name from test1 where id=${vari}‘]
  2. 1 and luonq

以上就是EPL和数据库交互的内容,针对普通的查询需求来说还是够用的,至于insert,update,delete我没有举例子,各位可以自己试试看可不可行。

时间: 2024-10-19 19:29:26

Esper学习之十:EPL语法(六)的相关文章

Esper学习之七:EPL语法(三)

1.Aggregation 和SQL一样,EPL也有Aggregation,即聚合函数.语法如下: [plain] view plaincopy aggregate_function([all|distinct] expression) aggregate_function就是聚合函数的名字,比如avg,sum等.expression通常是事件流的某个属性,也可以是不同事件流的多个属性,或者是属性和常量.函数之间的运算.举例如下. [plain] view plaincopy // 查询最新5秒

Esper学习之五:EPL语法(一)

上篇说到了Esper的Context,要是不了解的同学请参看<Esper学习之四:Context>,看过的同学如果还是不理解的话可以给我评论,我将会尽可能的解答.之前有些同学问我Context和Group by有什么区别,其实如果只是很简单的用Context,那么确实没太大区别,无非是在Context下select可以不包含group by修饰的属性.但是Group by明显没有Context强大,很多复杂的分组Group by是没法做到的.不过在能达到同样效果的情况下,我还是建议使用Grou

Esper学习之十二:EPL语法(八)

今天的内容十分重要,在Esper的应用中是十分常用的功能之一.它是一种事件集合,我们可以对这个集合进行增删查改,所以在复杂的业务场景中我们肯定不会缺少它.它就是Named Window. 由于本篇篇幅较长,希望各位童鞋慢慢阅读,并仔细研究文档中或者我给出的例子. 1.Create Named Window 本篇的开头有说过named window是一种事件集合,它可以存储一种类型或多种类型的事件.如果我们不移除named window中的事件,那么事件应该存在生命周期,否则事件过多会有内存溢出的

Esper学习之十五:Pattern(二)

转载请注明出处:http://blog.csdn.net/luonanqin 上一篇开始了新一轮语法--Pattern的讲解,一开始为大家普及了几个基础知识,其中有说到操作符.当时只是把它们都列举出来了,所以今天这篇就是专门详解这些操作符的,但是由于篇幅限制,本篇先会讲几个,剩余的后面几篇会逐个讲解. 1. Followed-by 如果各位有看过官方文档,应该会发现Followed-by的讲解是在比较靠后的位置,而放在第一的是Every关键字.我把它提前主要是因为其他的关键字结合Followed

Esper学习之十四:Pattern(一)

1. Pattern Atoms and Pattern operatorsPattern是通过原子事件和操作符组合在一起构成模板.原子事件有3类,操作符有4类,具体如下: 原子事件:1). 普通事件:包括POJO,Map,Array,XML2). 时间事件:包括间隔n个时间单位.crontab3). 自定义插件:用于观察特定事件的发生 操作符:1). 重复操作符:every, every-distinct, [num] and until2). 逻辑操作符:and, or, not3). 顺序

Esper学习之十一:EPL语法(七)

上一篇说到了EPL如何访问关系型数据库这种数据源,实际上别的数据源,比如:webservice.分布式缓存.非关系型数据库等等,Esper提供了统一的数据访问接口.然后今天会讲解如何创建另外一种事件类型——Schema. 1.Joining Method Invocation Results和执行sql的语法类似,调用方法的一种触发方式也是通过join别的事件的属性来达到效果,且调用方法的句子为from子句.语法如下: [plain] view plaincopy method:class_na

十分钟学习Python的进阶语法

(0)目录 VMware 下安装Ubuntu的吐血经历 零基础学习Shell编程 Linux下的makefile的妙用 Linux调试神器 -- gdb 十分钟学会Python的基本类型 分布式版本管理神器--GIT GIT文件的三种状态 & Git SSH秘钥问题 十分钟学习Python的进阶语法 配置SSH无密码访问及Linux热键.重启.kill进程 Java的不定长参数和Python的不定长参数对比 一:起因 (1)作为胶水语言的Python,可谓无处不在,快速开发原型网站:大数据处理等

JavaScript学习总结(十六)——Javascript闭包(Closure)

原文地址: http://www.cnblogs.com/xdp-gacl/p/3703876.html 闭包(closure)是Javascript语言的一个难点,也是它的特色, 很多高级应用都要依靠闭包实现.很早就接触过闭包这个概念了,但是一直糊里糊涂的,没有能够弄明白JavaScript的闭包到底是什么,有什么用,今天 在网上看到了一篇讲JavaScript闭包的文章(原文链接), 讲得非常好,这下算是彻底明白了JavaScript的闭包到底是个神马东东以及闭包的用途了,在此写出来和大家分

C++学习笔记十六-模板和泛型编程(二)

C++学习笔记十六-模板和泛型编程(二) 16.4 类模板成员 1.模板作用域中模板类型的引用: 通常,当使用类模板的名字的时候,必须指定模板形参.这一规则有个例外:在类本身的作用域内部,可以使用类模板的非限定名.例如,在默认构造函数和复制构造函数的声明中,名字 Queue 是 Queue<Type> 缩写表示.实质上,编译器推断,当我们引用类的名字时,引用的是同一版本.因此,复制构造函数定义其实等价于: Queue<Type>(const Queue<Type> &a