CrateDB初探(三):JDBC

目录

兼容性

添加Maven依赖

使用Java JDBC原生方式

准备工作

代码实现

数据操作

代码片段

Spring+CrateDB方式

配置文件

代码片段

扫描二维码关注公众号,回复: 15289119 查看本文章

DataSource的问题

Spring+MyBatis+CrateDB方式

配置文件

代码片段


这个系列的其他文章:

CrateDB初探(一):CrateDB集群的Docker部署

CrateDB初探(二):PARTITION, SHARDING AND REPLICATION

CrateDB初探(四):乐观并发控制 (Optimistic Concurrency Control )


本文简略地介绍了通过JDBC连接到CrateDB,并进行简单数据操作。

过程大致与连接到其他数据库(比如mysql)相似,需要注意驱动与db版本兼容性问题

兼容性

jdbc驱动与CrateDB版本需要遵循以下兼容性

注意:

  1. 当CrateDB版本在2.1.x以后,通过jdbc连接时必须提供一个用户名,默认是crate
  2. 实现细节方面,数据源无法使用(DataSource is not supported.)这里有疑问,见Spring+CrateDB小节

添加Maven依赖

  • 添加bintray仓库

<repository>
        <snapshots>
             <enabled>false</enabled>
        </snapshots>
        <id>cratedbmvn</id>
        <name>bintray</name>
        <url>http://dl.bintray.com/crate/crate</url>
  </repository>

  • pom.xml中添加crate-jdbc依赖(注册CrateDB JDBC驱动)

<!-- https://mvnrepository.com/artifact/io.crate/crate-jdbc -->
 <dependency>
      <groupId>io.crate</groupId>
      <artifactId>crate-jdbc</artifactId>
       <version>2.3.1</version>
  </dependency>

使用Java JDBC原生方式

准备工作

  • 通过docker启动一个实例

sudo docker run --name=crate-test1 -p 4211:4200 -p 5432:5432 --rm -d crate

注:5432是jdbc连接的默认端口,详见参数psql.port

  • 新增一个测试表

代码实现

采用properties方式建立jdbc链接,上文的兼容性说明中已经提到高版本db需要设置user参数(默认crate

Properties properties = new Properties();
properties.put("user", "crate");
Connection conn = DriverManager.getConnection(
                "crate://localhost:5432/", 
                properties);

或者使用CrateDriver(对connection URL的有效性进行检验)

Properties properties = new Properties();
properties.put("user", "crate");
// io.crate.client.jdbc.CrateDriver		
CrateDriver driver = new CrateDriver();
Connection conn = driver.connect("crate://localhost:5432/", properties);

默认schema为doc,如果要切换:conn.setSchema("my_schema");

参数:

  • user:DB版本2.1.x以上必须设置,如果没有自定义设置过数据库用户,则为CrateDB superuser, 即crate
  • strict:当设置为false,如果用到了CrateDB不支持的特性(比如事务)程序不会抛出异常,默默执行; 当设置为true,则会抛出异常。默认为false。
  • 其他参数见官方文档

数据操作

因为官方说无法使用datasource(实现细节),因此考虑用最原始的方式进行数据操作(这里有个疑问,实际是可以使用datasource的,见下面Spring+CrateDB小节)

插入

PreparedStatement ps2 =	conn.prepareStatement("INSERT INTO test_tab VALUES(2,'cj')"); 
ps2.execute();

查询

PreparedStatement ps = conn.prepareStatement("select name from test_tab where id=1");
ResultSet rs = ps.executeQuery();
while (rs.next()) {
	String name = rs.getString("name");
	System.out.println("rs: " + name);
}

关于FetchSize的设置

设置fetch size可以提高查询读取速度,在CrateDB中正确使用fetch size的姿势是需要将autoCommit设置为false

 * We are allowed to disable autoCommit (= manual commit) if strict mode is not enabled.
 * Manual commit is required for {@link org.postgresql.jdbc.PgStatement#setFetchSize(int)} to work correctly!
 * If autoCommit is true {@link org.postgresql.jdbc.PgStatement#executeInternal(CachedQuery, ParameterList, int)}
 * will never set the QueryExecutor.QUERY_FORWARD_CURSOR flag and therefore fetch all results at once instead of
 * batching them.

官方示例代码

在查询前statement.setFetchSize(10);

 /**
 * fetch size and execution flag is correctly appied if autoCommit == false
 */
@Test
public void testFetchSizeNotIgnoredIfManualCommit() throws Exception {
    try (Connection connection = DriverManager.getConnection(getConnectionString())) {
        connection.setAutoCommit(false);
        try (Statement statement = connection.createStatement()) {
            statement.setFetchSize(10);
            statement.execute("select * from sys.summits");
            ResultSet rs = statement.getResultSet();
            assertEquals(10, rs.getFetchSize());
            Field rowsField = rs.getClass().getDeclaredField("rows");
            rowsField.setAccessible(true);
            List rows = (List) rowsField.get(rs);
            assertEquals(10, rows.size());
        }
    }
}

代码片段

package nb.test.cratedb;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

/**
 * Hello world!
 *
 */
public class App {
	public static void main(String[] args) throws InterruptedException, SQLException {

		Connection conn = null;
		try {
			Properties properties = new Properties();
			properties.put("user", "crate");
			conn = DriverManager.getConnection("crate://localhost:5432/", properties);
			System.out.println("Connection: " + conn);

			PreparedStatement ps2 =	conn.prepareStatement("INSERT INTO test_tab VALUES(2,'cj')");
			ps2.execute();

			PreparedStatement ps = conn.prepareStatement("select id, name from test_tab");
			ResultSet rs = ps.executeQuery();
			while (rs.next()) {
				int id = rs.getInt("id");
				String name = rs.getString("name");
				System.out.println("id: " + id + ",   name: " + name);
			}

		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			conn.close();
		}

		Thread.sleep(10000);

	}
}

输出

官方的crate-jdbc使用范例

Spring+CrateDB方式

使用了原始的Spring-jdbc方式连接到CrateDB

配置文件

增加数据源依赖jar包

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-dbcp2</artifactId>
    <version>2.6.0</version>
</dependency>

db.properties

配置驱动类名、url、用户名(密码为空)

jdbc.driverClassName=io.crate.client.jdbc.CrateDriver
jdbc.url=crate://localhost:5432/
jdbc.username=crate
jdbc.password=

application.xml

配置数据源、JdbcTemplate的java bean

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://www.springframework.org/schema/beans" 
	xmlns:context="http://www.springframework.org/schema/context"   
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
     http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
     http://www.springframework.org/schema/context 
     http://www.springframework.org/schema/context/spring-context-4.0.xsd
     http://www.springframework.org/schema/aop
     http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
    
    
    <context:property-placeholder location="classpath:db.properties"/>
     
	<bean id="datasource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
		<property name="driverClassName" value="${jdbc.driverClassName}"></property>
		<property name="url" value="${jdbc.url}"></property>
		<property name="username" value="${jdbc.username}"></property>
		<property name="password" value="${jdbc.password}"></property>
		<property name="maxTotal" value="50" />
		<property name="maxWaitMillis" value="6000" />
		<property name="initialSize" value="10" />
		<property name="maxIdle" value="20"></property>
		<property name="minIdle" value="10" /> 
	</bean>
	
	<bean id="namedParameterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
		<constructor-arg ref="datasource" />
	</bean>
	
</beans>

代码片段

public static void main(String[] args) throws SQLException {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("application.xml");
		
		DataSource dbsource = (DataSource) ctx.getBean("datasource");
		NamedParameterJdbcTemplate namedTemplate = (NamedParameterJdbcTemplate) ctx.getBean("namedParameterJdbcTemplate");
		
		String sql = "SELECT id, name FROM doc.tmp1";
		Map<String, Object> paramsMap = new HashMap<String, Object>();
		SqlRowSet rowSet = namedTemplate.queryForRowSet(sql, paramsMap);
		while(rowSet.next()) {
			System.out.println("id: " + rowSet.getInt("id") + " , name: " + rowSet.getString("name"));
		}
	}

DataSource的问题

在CrateDB官方文档中提到

DataSource is not supported.

我的理解是还是可以引入第三方的数据源jar包来支持,比如本例中使用的dbcp2

为验证数据源是否真正起了作用,做个简陋的实验:

上例中conn2被关闭,但不影响conn查询数据,说明conn2和conn确实是两个从数据源中获得的不同连接。

Spring+MyBatis+CrateDB方式

引入MyBatis作为ORM框架,在上节基础上测试连接

配置文件

增加mybatis的jar包

<dependency>
	<groupId>org.mybatis</groupId>
	<artifactId>mybatis</artifactId>
	<version>3.4.5</version>
</dependency>

<dependency>
	<groupId>org.mybatis</groupId>
	<artifactId>mybatis-spring</artifactId>
	<version>1.3.2</version>
</dependency>

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration   
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"  
    "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
	<settings>
		<setting name="autoMappingUnknownColumnBehavior" value="WARNING" />
		<setting name="defaultStatementTimeout" value="25" />
	</settings>

	<typeAliases>
		<typeAlias type="nb.test.cratedb.User" alias="User" />
	</typeAliases>
</configuration>

增加mybatis的spring配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
     http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
     http://www.springframework.org/schema/context 
     http://www.springframework.org/schema/context/spring-context-4.0.xsd
     http://www.springframework.org/schema/aop
     http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">

	<bean id="sqlSessionFactory"
		class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="datasource" />

		<property name="mapperLocations">
			<list>
				<value>classpath:nb/test/orm/*.xml</value>
			</list>
		</property>
		<property name="configLocation"
			value="classpath:mybatis-config.xml" />
	</bean>
	
	
	<bean id="mapperScannerConfigurerMotan" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="nb.test.orm" />
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
    </bean>

</beans>

代码片段

实体类

public class User implements Serializable {

	private static final long serialVersionUID = 2686795246219114561L;
	private int id;
	private String name;

    /* 忽略getter, setter等代码 */
}

Dao接口

@MapperScan
public interface UserDao {
	public User queryUserById(int id);
}

Mapper

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="nb.test.orm.UserDao">
  	
	<select id="queryUserById" parameterType="int" resultType="User">
		SELECT id, name  FROM doc.tmp1 t
			WHERE t.id = #{id}
	</select>
	
</mapper>

Service实现,简单到可以忽略不计

@Service
public class UserService {

	@Autowired
	private UserDao userDao;
	
	public User getUser(int id) {
		return userDao.queryUserById(id);
	}
}

测试代码

public static void main(String[] args) {
		ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[]{"application.xml", "application-orm.xml"});
		UserService userService = (UserService) ctx.getBean("userService");
		User user = userService.getUser(1);
		System.out.println("User: " + user);
	}

猜你喜欢

转载自blog.csdn.net/gxf1027/article/details/104914382