深入理解h2和r2dbc-h2

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"简介","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文将会介绍R2DBC的H2实现r2dbc-h2的使用方法和要注意的事项。一起来看看吧。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"H2数据库简介","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"什么是H2数据库呢?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"H2是一个Java SQL database,它是一个开源的数据库,运行起来非常快。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"H2流行的原因是它既可以当做一个独立的服务器,也可以以一个嵌套的服务运行,并且支持纯内存形式运行。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"H2的jar包非常小,只有2M大小,所以非常适合做嵌套式数据库。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果作为嵌入式数据库,则需要将h2*.jar添加到classpath中。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面是一个简单的建立H2连接的代码:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"import java.sql.*;\npublic class Test {\n public static void main(String[] a)\n throws Exception {\n Connection conn = DriverManager.\n getConnection(\"jdbc:h2:~/test\", \"sa\", \"\");\n // add application code here\n conn.close();\n }\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果给定地址的数据库并不存在,","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"同时H2还提供了一个简单的管理界面,使用下面的命令就可以启动H2管理界面:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"java -jar h2*.jar\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"默认情况下访问http://localhost:8082就可以访问到管理界面:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/50/50c7908a9a005a5759c99fa048d6d752.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/23/23b3c4611a0feb61582e5a2aa877f5bf.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"r2dbc-h2","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"r2dbc-h2是r2dbc spi的一种实现。同样的使用r2dbc-h2也提供了两种h2的模式,一种是文件系统,一种是内存。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"同时还提供了事务支持,prepared statements和batch statements等特性的支持。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"r2dbc-h2的Maven依赖","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"要想使用r2dbc-h2,我们需要添加如下依赖:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"\n io.r2dbc\n r2dbc-h2\n ${version}\n\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果你体验snapshot版本,可以添加下面的依赖:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"\n io.r2dbc\n r2dbc-h2\n ${version}.BUILD-SNAPSHOT\n\n\n\n spring-libs-snapshot\n Spring Snapshot Repository\n https://repo.spring.io/libs-snapshot\n\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"建立连接","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"h2有两种连接方式,file和内存,我们分别看一下都是怎么建立连接的:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"ConnectionFactory connectionFactory = ConnectionFactories.get(\"r2dbc:h2:mem:///testdb\");\n\nPublisher extends Connection> connectionPublisher = connectionFactory.create();\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"ConnectionFactory connectionFactory = ConnectionFactories.get(\"r2dbc:h2:file//my/relative/path\");\n\nPublisher extends Connection> connectionPublisher = connectionFactory.create();\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们还可以通过ConnectionFactoryOptions来创建更加详细的连接信息:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"ConnectionFactoryOptions options = builder()\n .option(DRIVER, \"h2\")\n .option(PROTOCOL, \"...\") // file, mem\n .option(HOST, \"…\")\n .option(USER, \"…\")\n .option(PASSWORD, \"…\")\n .option(DATABASE, \"…\")\n .build();\n\nConnectionFactory connectionFactory = ConnectionFactories.get(options);\n\nPublisher extends Connection> connectionPublisher = connectionFactory.create();\n\n// Alternative: Creating a Mono using Project Reactor\nMono connectionMono = Mono.from(connectionFactory.create());\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上面的例子中,我们使用到了driver,protocol, host,username,password和database这几个选项,除此之外H2ConnectionOption中定义了其他可以使用的Option:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"public enum H2ConnectionOption {\n\n /**\n * FILE|SOCKET|NO\n */\n FILE_LOCK,\n\n /**\n * TRUE|FALSE\n */\n IFEXISTS,\n\n /**\n * Seconds to stay open or {@literal -1} to to keep in-memory DB open as long as the virtual machine is alive.\n */\n DB_CLOSE_DELAY,\n\n /**\n * TRUE|FALSE\n */\n DB_CLOSE_ON_EXIT,\n\n /**\n * DML or DDL commands on startup, use \"\\\\;\" to chain multiple commands\n */\n INIT,\n\n /**\n * 0..3 (0=OFF, 1=ERROR, 2=INFO, 3=DEBUG)\n */\n TRACE_LEVEL_FILE,\n\n /**\n * Megabytes (to override the 16mb default, e.g. 64)\n */\n TRACE_MAX_FILE_SIZE,\n\n /**\n * 0..3 (0=OFF, 1=ERROR, 2=INFO, 3=DEBUG)\n */\n TRACE_LEVEL_SYSTEM_OUT,\n\n LOG,\n\n /**\n * TRUE|FALSE\n */\n IGNORE_UNKNOWN_SETTINGS,\n\n /**\n * r|rw|rws|rwd (r=read, rw=read/write)\n */\n ACCESS_MODE_DATA,\n\n /**\n * DB2|Derby|HSQLDB|MSSQLServer|MySQL|Oracle|PostgreSQL|Ignite\n */\n MODE,\n\n /**\n * TRUE|FALSE\n */\n AUTO_SERVER,\n\n /**\n * A port number\n */\n AUTO_SERVER_PORT,\n\n /**\n * Bytes (e.g. 512)\n */\n PAGE_SIZE,\n\n /**\n * Number of threads (e.g. 4)\n */\n MULTI_THREADED,\n\n /**\n * TQ|SOFT_LRU\n */\n CACHE_TYPE,\n\n /**\n * TRUE|FALSE\n */\n PASSWORD_HASH;\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"当然还有最直接的database选项:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"r2dbc:h2:file//../relative/file/name\nr2dbc:h2:file///absolute/file/name\nr2dbc:h2:mem:///testdb\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们还可以通过H2特有的代码H2ConnectionFactory来创建:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"H2ConnectionFactory connectionFactory = new H2ConnectionFactory(H2ConnectionConfiguration.builder()\n .inMemory(\"...\")\n .option(H2ConnectionOption.DB_CLOSE_DELAY, \"-1\")\n .build());\n\nMono connection = connectionFactory.create();\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"CloseableConnectionFactory connectionFactory = H2ConnectionFactory.inMemory(\"testdb\");\n\nMono connection = connectionFactory.create();\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"参数绑定","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在使用prepare statement的时候,我们需要进行参数绑定:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"connection\n .createStatement(\"INSERT INTO person (id, first_name, last_name) VALUES ($1, $2, $3)\")\n .bind(\"$1\", 1)\n .bind(\"$2\", \"Walter\")\n .bind(\"$3\", \"White\")\n .execute()\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"除了$符号绑定之外,还支持index绑定,如下所示:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"Statement statement = connection.createStatement(\"SELECT title FROM books WHERE author = $1 and publisher = $2\");\nstatement.bind(0, \"John Doe\");\nstatement.bind(1, \"Happy Books LLC\");\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"批处理","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们来看下r2dbc-h2是怎么来进行批处理的:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"Batch batch = connection.createBatch();\nPublisher extends Result> publisher = batch.add(\"SELECT title, author FROM books\")\n .add(\"INSERT INTO books VALUES('John Doe', 'HappyBooks LLC')\")\n .execute();\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"事务和Savepoint","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"r2dbc还支持事务和savepoint,我们可以在事务中rollback到特定的savepoint。具体的代码如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"Publisher begin = connection.beginTransaction();\n\nPublisher insert1 = connection.createStatement(\"INSERT INTO books VALUES ('John Doe')\").execute();\n\nPublisher savepoint = connection.createSavepoint(\"savepoint\");\n\nPublisher insert2 = connection.createStatement(\"INSERT INTO books VALUES ('Jane Doe')\").execute();\n\n\nPublisher partialRollback = connection.rollbackTransactionToSavepoint(\"savepoint\");\n\n\nPublisher commit = connection.commit();\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"italic","attrs":{}}],"text":"本文作者:flydean程序那些事","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"italic","attrs":{}}],"text":"本文链接:","attrs":{}},{"type":"link","attrs":{"href":"http://www.flydean.com/r2dbc-h2-in-depth/","title":null},"content":[{"type":"text","text":"http://www.flydean.com/r2dbc-h2-in-depth/","attrs":{}}],"marks":[{"type":"italic"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"italic","attrs":{}}],"text":"本文来源:flydean的博客","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"italic","attrs":{}}],"text":"欢迎关注我的公众号:「程序那些事」最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!","attrs":{}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章