因用户需要使用Zipkin追踪数据库调用链,记录整个调用过程的耗时及sql语句信息。查看Zipkin官网暂不适配达梦数据库接口,故作如下适配学习记录。
(1)Eclipse新建Springboot项目
(2)导入依赖的jar包或者新建lib目录
(3)新建JdbcTemplateConfig.java
package com.example.demo;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
@Configuration
public class JdbcTemplateConfig {
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("dm.jdbc.driver.DmDriver");
dataSource.setUrl("jdbc:dm://192.168.206.147:5237?user=SYSDBA");
dataSource.setUsername("SYSDBA");
dataSource.setPassword("SYSDBA");
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(dataSource());
}
}
(4)新建RestTemplateConfig.java
package com.example.demo;
import java.nio.charset.Charset;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
RestTemplate restTemplate = new RestTemplate(factory);
// 支持中文编码
restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(Charset.forName("UTF-8")));
return restTemplate;
}
}
(5)新建ZipkinConfig.java,在此定制需要追踪的tag
package com.example.demo;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
@Configuration
public class ZipkinConfig {
@Autowired
private Tracer tracer;
/*
* @Autowired private DataSource dataSource;
*/
@Bean("zipkinRestTemplate")
public RestTemplate createRestTemplate() {
RestTemplate restTemplate = new RestTemplate(simpleClientHttpRequestFactory());
List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors();
interceptors.add(new ClientHttpRequestInterceptor() {
@Override
public ClientHttpResponse intercept(org.springframework.http.HttpRequest request, byte[] body,
org.springframework.http.client.ClientHttpRequestExecution execution) throws java.io.IOException {
if (tracer != null) {
request.getHeaders().add("X-B3-TraceId", tracer.currentSpan().context().traceId());
request.getHeaders().add("X-B3-SpanId", tracer.currentSpan().context().spanId());
}
return execution.execute(request, body);
}
});
restTemplate.setInterceptors(interceptors);
return restTemplate;
}
/*
* @Bean public JdbcTemplate jdbcTemplate(DataSource dataSource) { return new
* JdbcTemplate(dataSource); }
*/
@Bean
public TraceJdbcTemplateAspect traceJdbcTemplateAspect() {
return new TraceJdbcTemplateAspect();
}
@Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setReadTimeout(5000);
factory.setConnectTimeout(5000);
return factory;
}
@Aspect
@Component
public static class TraceJdbcTemplateAspect {
private final static Pattern PATTERN_SELECT = Pattern.compile("\\s*select.+from\\s+([^\\s]+)(\\s+.+)?\\s*",
Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
private final static Pattern PATTERN_INSERT = Pattern.compile("\\s*insert\\s+into\\s+([^\\s]+)(\\s+.+)?\\s*",
Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
private final static Pattern PATTERN_UPDATE = Pattern.compile("\\s*update\\s+([^\\s]+)(\\s+.+)?\\s*",
Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
private final static Pattern PATTERN_DELETE = Pattern.compile("\\s*delete\\s+from\\s+([^\\s]+)(\\s+.+)?\\s*",
Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
@Autowired
private Tracer tracer;
@Pointcut("execution(* org.springframework.jdbc.core.JdbcTemplate.queryForList*(..)) ||"
+ "execution(* org.springframework.jdbc.core.JdbcTemplate.update*(..))")
public void executeQuery() {
}
@Around("executeQuery()")
public Object queryAround(ProceedingJoinPoint pjp) throws Throwable {
String sql = (String) pjp.getArgs()[0];
// System.out.println(sql);
Span span = tracer.nextSpan().name(getOperation(sql));
// System.out.println(span);
try {
long startTime = System.currentTimeMillis();
Object result = pjp.proceed();
long endTime = System.currentTimeMillis();
span.tag("sql", sql);
// span.tag("dataSource", dataSource.getClass().toString());
span.tag("time", (endTime - startTime) + "ms");
return result;
} catch (Exception e) {
span.tag("error", e.getMessage());
throw e;
} finally {
span.end();
}
}
private String getOperation(String sql) {
if (sql != null && !"".equals(sql.trim())) {
Matcher matcherSelect = PATTERN_SELECT.matcher(sql);
if (matcherSelect.matches()) {
return "SELECT FROM " + matcherSelect.group(1).trim();
}
Matcher matcherInsert = PATTERN_INSERT.matcher(sql);
if (matcherInsert.matches()) {
return "INSERT INTO " + matcherInsert.group(1).trim();
}
Matcher matcherUpdate = PATTERN_UPDATE.matcher(sql);
if (matcherUpdate.matches()) {
return "UPDATE " + matcherUpdate.group(1).trim();
}
Matcher matcherDelete = PATTERN_DELETE.matcher(sql);
if (matcherDelete.matches()) {
return "DELETE FROM " + matcherDelete.group(1).trim();
}
}
return "SQL";
}
}
}
(6)新建ZipkinDmApplication.java
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.client.RestTemplate;
@ComponentScan(basePackages = { "com.example.demo" })
//@EnableZipkinServer
//@EnableDiscoveryClient
@SpringBootApplication
public class ZipkinDemoApplication {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(ZipkinDemoApplication.class, args);
}
}
(7)新建ZipkinDmController.java
package com.example.demo;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
//@EnableWebMvc
@ServletComponentScan
@RestController
@RequestMapping(value = "/db", method = { RequestMethod.GET, RequestMethod.POST })
public class ZipkinDmController {
//注入 jdbcTemplate 模板对象
private final JdbcTemplate jdbcTemplate;
@Autowired
public ZipkinDmController(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
// 编写测试方法
// 浏览器访问 http://localhost:8045/db/test1 ,返回sql执行结果。
@RequestMapping("/test1")
@ResponseBody
public String test1() {
String sql1 = "DELETE FROM test WHERE id=1;COMMIT;";
jdbcTemplate.execute(sql1);
String sql2 = "SELECT name FROM test;";
List<Map<String, Object>> result1 = jdbcTemplate.queryForList(sql2);
return "Query name result: " + result1.toString();
}
// 浏览器访问 http://localhost:8045/db/test2 ,返回sql执行结果。
@RequestMapping("/test2")
@ResponseBody
public String test2() {
String sql3 = "INSERT INTO test VALUES (4,'FOUR');COMMIT;";
jdbcTemplate.execute(sql3);
String sql4 = "UPDATE test SET name='Tom' WHERE id=2;COMMIT;";
jdbcTemplate.execute(sql4);
String sql5 = "SELECT name FROM test;";
List<Map<String, Object>> result2 = jdbcTemplate.queryForList(sql5);
return "Query name result2: " + result2.toString();
}
}
(8)修改application.propertites
server.port=8045
spring.datasource.driver-class-name=dm.jdbc.driver.DmDriver
spring.datasource.url=jdbc:dm://192.168.206.147:5237
spring.datasource.username=SYSDBA
spring.datasource.password=SYSDBA
spring.main.allow-bean-definition-overriding=true
spring.application.name=ZIPKIN_DEMO
# zipkin
spring.zipkin.base-url=http://192.168.206.147:9411/
spring.sleuth.sampler.probability=1.0
# logging.level.org.springframework.jdbc.core.JdbcTemplate=DEBUG
(9)修改pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>ZIPKIN_DEMO</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>ZIPKIN_DEMO</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>2020.0.3</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
(1)Eclipse新建Springboot项目
(2)导入依赖的jar包或者新建lib目录
(3)新建JdbcTemplateConfig.java,主要修改数据库连接串URL配置接口。
package com.example.demo;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
@Configuration
public class JdbcTemplateConfig {
@Bean
/* DM */
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("dm.jdbc.driver.DmDriver");
dataSource.setUrl(
"jdbc:dm://192.168.206.147:5237/?customFilter=com.dameng.zipkin.DmZipkinCustom&zipkinServiceName=ZIPKIN_DM");
dataSource.setUsername("SYSDBA");
dataSource.setPassword("SYSDBA");
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(dataSource());
}
}
(4)新建ZipkinDmApplication.java
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ZipkinDmApplication {
public static void main(String[] args) {
SpringApplication.run(ZipkinDmApplication.class, args);
}
}
(5)新建ZipkinDmController.java
package com.example.demo;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
//@EnableWebMvc
@ServletComponentScan
@RestController
@RequestMapping(value = "/db", method = { RequestMethod.GET, RequestMethod.POST })
public class ZipkinDmController {
//注入 jdbcTemplate 模板对象
private final JdbcTemplate jdbcTemplate;
@Autowired
public ZipkinDmController(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
// 编写测试方法
// 浏览器访问 http://localhost:8045/db/test1 ,返回sql执行结果。
@RequestMapping("/test1")
@ResponseBody
public String test1() {
String sql1 = "DELETE FROM test WHERE id=1;";
jdbcTemplate.execute(sql1);
String sql2 = "SELECT name FROM test";
List<Map<String, Object>> result1 = jdbcTemplate.queryForList(sql2);
return "Query name result: " + result1.toString();
}
// 浏览器访问 http://localhost:8045/db/test2 ,返回sql执行结果。
@RequestMapping("/test2")
@ResponseBody
public String test2() {
String sql3 = "INSERT INTO test VALUES (4,'FOUR');";
jdbcTemplate.execute(sql3);
String sql4 = "UPDATE test SET name='Tom' WHERE id=2;";
jdbcTemplate.execute(sql4);
String sql5 = "SELECT name FROM test;";
List<Map<String, Object>> result2 = jdbcTemplate.queryForList(sql5);
return "Query name result2: " + result2.toString();
}
}
(6)修改application.propertites
server.port=8045
spring.datasource.driver-class-name=dm.jdbc.driver.DmDriver
spring.datasource.url=jdbc:dm://192.168.206.147:5237
spring.datasource.username=SYSDBA
spring.datasource.password=SYSDBA
spring.main.allow-bean-definition-overriding=true
spring.application.name=ZIPKIN_DM
# zipkin
spring.zipkin.base-url=http://192.168.206.147:9411/
spring.sleuth.sampler.probability=1.0
# logging.level.org.springframework.jdbc.core.JdbcTemplate=DEBUG
(7)修改pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>ZIPKIN_DM</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>ZIPKIN_DM</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>2020.0.3</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
(1)打开zipkin服务
java -jar zipkin-server-2.24.2-exec.jar
(2)客户端执行测试程序
在JdbcTemplateConfig.java文件中修改url连接串,运行demo。
(3)在数据库中创建测试表:
CREATE TABLE test(id int,name char(200));
INSERT INTO test VALUES(1,'ONE'),(2,'TWO'),(3,'THREE');
COMMIT;
SELECT * FROM test;
(4)浏览器访问:http://localhost:8045/db/test1
(5)浏览器访问:http://192.168.206.147:9411/zipkin/
Zipkin页面点击 > RUN QUERY 可以看到追踪结果:
Zipkin页面点击 > SHOW 可以查看追踪详情:
点击子项可以查看到执行的sql语句及耗时:
文章
阅读量
获赞