从零到一:Spring Boot快速接入金仓数据库实战

从零到一:Spring Boot快速接入金仓数据库实战

一个真实的故事

去年接手一个项目,团队用Spring Boot + MySQL开发了一套内部管理系统,眼看要上线了,客户突然提出要换成国产数据库。

开发负责人当场就懵了:"代码要不要大改?驱动支不支持?事务会不会出问题?"

我当时正好在做金仓数据库的技术调研,就主动接了这个任务。结果从修改配置到跑通测试,前后不到一个小时。今天就把这次实战经验整理出来,给遇到同样需求的团队做个参考。

一、准备工作:连接信息从哪里拿

在开始写代码之前,先要拿到金仓数据库的连接信息。如果你不是DBA,可以找运维或DBA要以下信息:

bash 复制代码
# 典型连接命令示例
./ksql -U system -d test -h 192.168.1.100 -p 54321

参数说明:

  • -U system:用户名,管理员默认是system
  • -d test:要连接的数据库名
  • -h 192.168.1.100:数据库服务器IP
  • -p 54321:端口号,默认是54321

拿到这些信息后,整理成JDBC URL格式:

复制代码
jdbc:kingbase8://host:port/database

比如:

复制代码
jdbc:kingbase8://192.168.1.100:54321/test

二、项目搭建:从零开始

2.1 创建Spring Boot项目

用IDEA新建Spring Boot项目,或者用Spring Initializr生成。我习惯用IDEA直接创建,方便管理。

项目结构如下:

复制代码
java-kingbase-springboot/
├── pom.xml
├── src/
│   ├── main/
│   │   ├── java/com/kingbase/testspringboot/
│   │   │   ├── TestSpringbootApplication.java
│   │   │   ├── dao/
│   │   │   │   ├── UserDao.java
│   │   │   │   └── impl/UserDaoImpl.java
│   │   │   └── entity/User.java
│   │   └── resources/application.properties
│   └── test/java/com/kingbase/testspringboot/
│       └── TestSpringbootApplicationTests.java
└── target/

2.2 配置pom.xml:依赖是重点

pom.xml中最关键的是金仓数据库驱动的依赖:

xml 复制代码
<dependency>
    <groupId>cn.com.kingbase</groupId>
    <artifactId>kingbase8</artifactId>
    <version>9.0.0</version>
</dependency>

完整的pom.xml如下:

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.7.11</version>
        <relativePath/>
    </parent>
    
    <groupId>com.kingbase</groupId>
    <artifactId>java-kingbase-springboot</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>java-kingbase-springboot</name>
    <description>Spring Boot连接金仓数据库示例</description>
    
    <properties>
        <java.version>1.8</java.version>
    </properties>
    
    <dependencies>
        <!-- Spring Boot核心依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        
        <!-- Spring Boot JDBC支持 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        
        <!-- 金仓数据库驱动,最关键的一步 -->
        <dependency>
            <groupId>cn.com.kingbase</groupId>
            <artifactId>kingbase8</artifactId>
            <version>9.0.0</version>
        </dependency>
        
        <!-- 测试依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

踩坑提醒 :金仓驱动groupId是cn.com.kingbase,不是com.kingbase8,写错了会拉不到依赖。

2.3 配置文件application.properties

src/main/resources/application.properties中配置数据源:

properties 复制代码
# 金仓数据库驱动
spring.datasource.driverClassName=com.kingbase8.Driver

# 连接URL:jdbc:kingbase8://IP:端口/数据库名
spring.datasource.url=jdbc:kingbase8://localhost:54321/test

# 用户名和密码
spring.datasource.username=system
spring.datasource.password=你的密码

三、代码实现:三层结构

3.1 实体类:User.java

java 复制代码
package com.kingbase.testspringboot.entity;

public class User {
    private Long id;
    private String name;
    
    // 无参构造方法(必须)
    public User() {
    }
    
    // 带参构造方法
    public User(Long id, String name) {
        this.id = id;
        this.name = name;
    }
    
    // getter和setter
    public Long getId() {
        return id;
    }
    
    public void setId(Long id) {
        this.id = id;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    @Override
    public String toString() {
        return "User{id=" + id + ", name='" + name + "'}";
    }
}

3.2 DAO接口:UserDao.java

java 复制代码
package com.kingbase.testspringboot.dao;

import com.kingbase.testspringboot.entity.User;
import java.util.List;

public interface UserDao {
    // 插入用户
    boolean insertUser(User user);
    
    // 根据ID删除
    boolean deleteById(Long id);
    
    // 更新用户
    boolean updateUser(User user);
    
    // 根据ID查询
    User selectUserById(Long id);
    
    // 查询所有用户
    List<User> selectAllUsers();
}

3.3 DAO实现:UserDaoImpl.java

java 复制代码
package com.kingbase.testspringboot.dao.impl;

import com.kingbase.testspringboot.dao.UserDao;
import com.kingbase.testspringboot.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import java.util.List;

@Repository("userDao")
public class UserDaoImpl implements UserDao {
    
    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    @Override
    public boolean insertUser(User user) {
        String sql = "insert into test_springboot(id, name) values(?, ?)";
        Object[] params = {user.getId(), user.getName()};
        return jdbcTemplate.update(sql, params) > 0;
    }
    
    @Override
    public boolean deleteById(Long id) {
        String sql = "delete from test_springboot where id = ?";
        Object[] params = {id};
        return jdbcTemplate.update(sql, params) > 0;
    }
    
    @Override
    public boolean updateUser(User user) {
        String sql = "update test_springboot set name = ? where id = ?";
        Object[] params = {user.getName(), user.getId()};
        return jdbcTemplate.update(sql, params) > 0;
    }
    
    @Override
    public User selectUserById(Long id) {
        String sql = "select * from test_springboot where id = ?";
        Object[] params = {id};
        return jdbcTemplate.queryForObject(
            sql, 
            params, 
            new BeanPropertyRowMapper<>(User.class)
        );
    }
    
    @Override
    public List<User> selectAllUsers() {
        String sql = "select * from test_springboot";
        return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(User.class));
    }
}

注意点BeanPropertyRowMapper要求数据库字段名和Java属性名保持一致,或者用下划线转驼峰的映射规则。这里表字段是idname,和User类的属性名一致,所以能自动映射。

3.4 启动类:TestSpringbootApplication.java

java 复制代码
package com.kingbase.testspringboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class TestSpringbootApplication {
    public static void main(String[] args) {
        SpringApplication.run(TestSpringbootApplication.class, args);
    }
}

四、测试验证:跑通整个流程

4.1 测试类:TestSpringbootApplicationTests.java

java 复制代码
package com.kingbase.testspringboot;

import com.kingbase.testspringboot.dao.UserDao;
import com.kingbase.testspringboot.entity.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.jdbc.core.JdbcTemplate;
import java.util.List;

@SpringBootTest
public class TestSpringbootApplicationTests {
    
    @Autowired
    private UserDao userDao;
    
    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    @Test
    public void contextLoads() {
        // 1. 删除旧表(如果存在)
        try {
            jdbcTemplate.execute("drop table test_springboot");
            System.out.println("test_springboot delete successfully!");
        } catch (Exception ignore) {
            // 表不存在时忽略异常
        }
        
        // 2. 创建新表
        jdbcTemplate.execute("create table test_springboot (" +
            "id int primary key, " +
            "name varchar(50))");
        System.out.println("test_springboot create successfully!");
        
        // 3. 插入10条数据
        for (int i = 1; i <= 10; i++) {
            userDao.insertUser(new User((long) i, "insert" + i));
        }
        
        // 4. 删除id=1的数据
        userDao.deleteById(1L);
        
        // 5. 更新id=2的数据
        userDao.updateUser(new User(2L, "update"));
        
        // 6. 查询id=2的数据
        User user = userDao.selectUserById(2L);
        System.out.println("user = " + user);
        
        // 7. 查询所有数据
        List<User> userList = userDao.selectAllUsers();
        userList.forEach(System.out::println);
    }
}

4.2 运行结果

复制代码
test_springboot delete successfully!
test_springboot create successfully!
user = User{id=2, name='update'}
User{id=2, name='update'}
User{id=3, name='insert3'}
User{id=4, name='insert4'}
User{id=5, name='insert5'}
User{id=6, name='insert6'}
User{id=7, name='insert7'}
User{id=8, name='insert8'}
User{id=9, name='insert9'}
User{id=10, name='insert10'}

从输出可以看到:

  • 建表、删表成功
  • 插入10条数据成功
  • 删除id=1成功
  • 更新id=2成功
  • 查询结果正确

五、常见问题与解决方案

5.1 驱动类找不到

报错java.lang.ClassNotFoundException: com.kingbase8.Driver

原因:pom.xml中没有正确引入金仓驱动,或者scope设置不当

解决 :检查pom.xml中是否有kingbase8依赖,确保没有设置scope=test

5.2 连接被拒绝

报错Connection refused

原因:IP、端口、数据库名填错了,或者金仓服务没启动

解决

  1. 先用ksql命令行测试能否连接
  2. 检查防火墙是否开放了端口
  3. 确认数据库名是否正确(区分大小写)

5.3 表名或字段名大小写问题

金仓默认是大小写不敏感的,但如果建表时用了双引号,就会变成大小写敏感。建议统一用小写,避免麻烦。

sql 复制代码
-- 推荐写法
CREATE TABLE test_springboot (id INT, name VARCHAR(50));

-- 避免这种写法,会带来困扰
CREATE TABLE "Test_SpringBoot" ("Id" INT, "Name" VARCHAR(50));

六、生产环境建议

示例代码跑通后,在实际项目中还需要注意几点:

1. 使用连接池

Spring Boot默认使用HikariCP,配置如下:

properties 复制代码
spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.connection-timeout=30000

2. 密码不要硬编码

properties 复制代码
# 使用环境变量
spring.datasource.password=${KINGBASE_PASSWORD}

# 或使用配置中心

3. 事务管理

在Service层使用@Transactional注解:

java 复制代码
@Service
public class UserService {
    @Autowired
    private UserDao userDao;
    
    @Transactional
    public void updateUserWithLog(User user, String log) {
        userDao.updateUser(user);
        // 记录日志等其他操作
    }
}

写在最后

从MySQL切换到金仓,Spring Boot项目需要改动的其实就两处:pom.xml加驱动、application.properties改URL。如果代码里没有用数据库特有的方言,基本能做到零修改迁移。

这次实战经历也让我对金仓的JDBC驱动有了更多信心------兼容性不错,性能也稳定。如果你的团队正在做技术选型或国产化改造,不妨动手试试。

相关推荐
麦聪聊数据19 分钟前
企业数据市场建设(三):API 化服务封装,让数据开箱即用、避免重复开发
数据库
脱胎换骨-军哥23 分钟前
C++数据库存储引擎内核开发:B+树索引与MVCC并发控制的完整实现
数据库·c++·b树
麦聪聊数据31 分钟前
企业数据市场建设(四):流程闭环与价值运营,让数据市场真正转起来
运维·数据库
正儿八经的少年38 分钟前
redis 的大 key 和热 key 详解
数据库·redis·缓存
AI砖家42 分钟前
多智能体系统实战:架构设计、数据库表设计与 Skill 体系
数据库·多智能体·skill·agent架构设计·agengt
止语Lab1 小时前
好的 DX 不等于少写代码——三种语言的摩擦力设计课
后端
吃饱了得干活1 小时前
别再手动解析 LLM 输出了!LangChain 四种结构化输出方案对比
后端·python·langchain
程序员天天困1 小时前
Arthas trace 命令怎么用?一行定位最慢那行代码
jvm·后端
Huiturn1 小时前
GPT 5.6 连续编码 10 小时,纯 Python 啃下 Word 二进制格式——doc2docx 实现拆解
后端
dkbnull1 小时前
Spring Boot请求处理组件对比详解
java·spring boot