Table of contents
Other articles in this series:
A Preliminary Study of CrateDB (1): Docker Deployment of CrateDB Cluster
CrateDB Preliminary Study (2): PARTITION, SHARDING AND REPLICATION
CrateDB Preliminary Study (4): Optimistic Concurrency Control (Optimistic Concurrency Control)
This article briefly introduces connecting to CrateDB through JDBC and performing simple data operations.
The process is roughly similar to connecting to other databases (such as mysql), and you need to pay attention to driver and db version compatibility issues
compatibility
The jdbc driver and CrateDB version need to comply with the following compatibility
Notice:
- When the CrateDB version is later than 2.1.x, a user name must be provided when connecting through jdbc, and the default is crate
- In terms of implementation details , the data source cannot be used ( DataSource is not supported. ) There are doubts here, see the Spring+CrateDB section
Add Maven dependency
- Add bintray repository
<repository>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>cratedbmvn</id>
<name>bintray</name>
<url>http://dl.bintray.com/crate/crate</url>
</repository>
- Add crate-jdbc dependency in pom.xml (register CrateDB JDBC driver)
<!-- https://mvnrepository.com/artifact/io.crate/crate-jdbc -->
<dependency>
<groupId>io.crate</groupId>
<artifactId>crate-jdbc</artifactId>
<version>2.3.1</version>
</dependency>
Use Java JDBC native way
Preparation
- Start an instance via docker
sudo docker run --name=crate-test1 -p 4211:4200 -p 5432:5432 --rm -d crate
Note: 5432 is the default port for jdbc connection, see parameter psql.port for details
- Add a new test table
Code
Use the properties method to establish the jdbc link. It has been mentioned in the compatibility description above that the user parameter (default crate ) needs to be set for the high version db.
Properties properties = new Properties();
properties.put("user", "crate");
Connection conn = DriverManager.getConnection(
"crate://localhost:5432/",
properties);
Or use CrateDriver (check the validity of the 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);
The default schema is doc, if you want to switch:conn.setSchema("my_schema");
参数:
- user: DB version 2.1.x or later must be set, if no custom database user has been set, it will be CrateDB superuser, namely crate
- strict: When set to false, if features not supported by CrateDB (such as transactions) are used, the program will not throw an exception and execute silently; when set to true, an exception will be thrown. The default is false.
- For other parameters, see the official documentation
data manipulation
Because the official said that datasource ( implementation details ) cannot be used , consider using the most primitive way for data manipulation (there is a question here, in fact, datasource can be used, see the Spring+CrateDB section below)
insert
PreparedStatement ps2 = conn.prepareStatement("INSERT INTO test_tab VALUES(2,'cj')");
ps2.execute();
Inquire
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);
}
About FetchSize settings
Setting the fetch size can improve the query reading speed. To use the fetch size correctly in CrateDB, you need to set autoCommit to 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.
Official sample code
Before the query 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());
}
}
}
code segment
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);
}
}
output
Official crate-jdbc usage example
Spring+CrateDB method
Use the original Spring-jdbc way to connect to CrateDB
configuration file
Add data source dependency jar package
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.6.0</version>
</dependency>
db.properties
Configure driver class name, url, user name (password is empty)
jdbc.driverClassName=io.crate.client.jdbc.CrateDriver
jdbc.url=crate://localhost:5432/
jdbc.username=crate
jdbc.password=
application.xml
Configure data source, java bean of JdbcTemplate
<?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>
code segment
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"));
}
}
Problems with DataSources
Mentioned in the official CrateDB documentation
DataSource is not supported.
My understanding is that third-party data source jar packages can still be introduced to support, such as dbcp2 used in this example
To verify whether the data source really works, do a simple experiment:
In the above example, conn2 is closed, but it does not affect the query data of conn, indicating that conn2 and conn are indeed two different connections obtained from the data source.
Spring+MyBatis+CrateDB method
Introduce MyBatis as an ORM framework and test the connection based on the previous section
configuration file
Add the jar package of mybatis
<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>
Add the spring configuration file of mybatis
<?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>
code segment
Entity class
public class User implements Serializable {
private static final long serialVersionUID = 2686795246219114561L;
private int id;
private String name;
/* 忽略getter, setter等代码 */
}
Dao interface
@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 implementation, so simple that it can be ignored
@Service
public class UserService {
@Autowired
private UserDao userDao;
public User getUser(int id) {
return userDao.queryUserById(id);
}
}
test code
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);
}