Spring JDBCTemplate 实战大全:从 CRUD 到高级技巧,一篇搞定!(应用篇一)

在这里插入图片描述

肖哥弹架构 跟大家“弹弹” Spring JDBCTemplate设计与实战应用,需要代码关注

欢迎 点赞,点赞,点赞。

关注公号Solomon肖哥弹架构获取更多精彩内容

历史热点文章

📌 还在为 Spring JDBCTemplate 的操作发愁?本文为你揭秘所有核心用法!从基础的增删改查(CRUD)到多表关联、分页查询、流式处理、动态 SQL、批处理优化,再到存储过程调用和数据库元数据操作,一网打尽!

亮点内容

  • 高效查询:分页、多表关联、复合主键、复杂条件动态构建
  • 性能优化:流式处理大数据、自适应批处理、避免内存溢出
  • 高级技巧:JSON 字段处理、乐观锁实现、存储过程调用
  • 实战代码:每个技巧均附完整示例,即学即用!

一、查询操作

在这里插入图片描述

1. 基本 CRUD 操作

  • query() :执行查询操作

    List<User> users = jdbcTemplate.query("SELECT * FROM users", new BeanPropertyRowMapper<>(User.class));
    
  • queryForObject() :查询单个对象

    int count = jdbcTemplate.queryForObject("SELECT COUNT(*) FROM users", Integer.class);
    
  • queryForObject() :查询JavaBean对象(多列映射)

    // 使用RowMapper映射到JavaBean
    String sql = "SELECT id, name, email FROM users WHERE id = ?";
    User user = jdbcTemplate.queryForObject(
        sql, 
        new BeanPropertyRowMapper<>(User.class), 
        123);
    
    // 或者使用Lambda表达式
    User user = jdbcTemplate.queryForObject(
        sql,
        (rs, rowNum) -> {
            User u = new User();
            u.setId(rs.getLong("id"));
            u.setName(rs.getString("name"));
            u.setEmail(rs.getString("email"));
            return u;
        },
        123);
    
  • 分页查询实现

    public List<User> findUsersByPage(int pageNum, int pageSize) {
        String sql = "SELECT * FROM users LIMIT ? OFFSET ?";
        int offset = (pageNum - 1) * pageSize;
        return jdbcTemplate.query(sql, new Object[]{pageSize, offset}, 
            new BeanPropertyRowMapper<>(User.class));
    }
    

主要的方法签名有:

<T> T queryForObject(String sql, Class<T> requiredType)
<T> T queryForObject(String sql, Class<T> requiredType, Object... args)
<T> T queryForObject(String sql, RowMapper<T> rowMapper)
<T> T queryForObject(String sql, RowMapper<T> rowMapper, Object... args)
<T> T queryForObject(String sql, Object[] args, Class<T> requiredType)
<T> T queryForObject(String sql, Object[] args, RowMapper<T> rowMapper)

2. 多表关联查询处理

public List<OrderWithUser> findOrdersWithUsers() {
    String sql = "SELECT o.*, u.name as user_name, u.email as user_email " +
                 "FROM orders o JOIN users u ON o.user_id = u.id";
    
    return jdbcTemplate.query(sql, (rs, rowNum) -> {
        Order order = new Order();
        order.setId(rs.getLong("id"));
        order.setOrderDate(rs.getDate("order_date"));
        
        User user = new User();
        user.setName(rs.getString("user_name"));
        user.setEmail(rs.getString("user_email"));
        
        return new OrderWithUser(order, user);
    });
}

3. 复合主键处理

public User findById(CompositeKey key) {
    String sql = "SELECT * FROM users WHERE department_id = ? AND employee_id = ?";
    return jdbcTemplate.queryForObject(sql, 
        new Object[]{key.getDepartmentId(), key.getEmployeeId()},
        new BeanPropertyRowMapper<>(User.class));
}

4. 复杂查询构建

public class UserQueryCondition {
    private String name;        // 姓名模糊查询条件
    private Integer minAge;     // 最小年龄条件
    private Integer maxAge;     // 最大年龄条件
    private String email;       // 邮箱精确查询条件
    private Boolean active;     // 是否激活状态
    private Date createTimeFrom; // 创建时间范围-开始
    private Date createTimeTo;   // 创建时间范围-结束
    
    // getter 和 setter 方法
    //setter...
}

public List<User> findUsersByCondition(UserQueryCondition condition) {
    String sql = "SELECT * FROM users WHERE 1=1";
    List<Object> params = new ArrayList<>();
    
    if (condition.getName() != null) {
        sql += " AND name LIKE ?";
        params.add("%" + condition.getName() + "%");
    }
    if (condition.getMinAge() != null) {
        sql += " AND age >= ?";
        params.add(condition.getMinAge());
    }
    
    return jdbcTemplate.query(sql, params.toArray(), 
        new BeanPropertyRowMapper<>(User.class));
}

5. 大数据量处理(流式查询)

List<User> adultUsers;
try (Stream<User> stream = jdbcTemplate.queryForStream(
    "SELECT * FROM users", 
    new BeanPropertyRowMapper<>(User.class))) {
    
    adultUsers = stream.filter(u -> u.getAge() > 18)
                     .collect(Collectors.toList());
}

// 现在可以使用adultUsers列表
adultUsers.forEach(user -> {
    // 处理每个成年用户
});

//------------------------------------------------------------
public Map<String, List<User>> groupUsersByDepartment() {
    String sql = "SELECT * FROM users";
    
    try (Stream<User> userStream = jdbcTemplate.queryForStream(sql, 
        new BeanPropertyRowMapper<>(User.class))) {
        
        return userStream
            .filter(u -> u.getDepartment() != null)
            .collect(Collectors.groupingBy(User::getDepartment));
    }
}

6. 动态 SQL 构建

public List<User> searchUsers(Map<String, Object> params) {
    String baseSql = "SELECT * FROM users";
    List<Object> values = new ArrayList<>();
    
    if (!params.isEmpty()) {
        baseSql += " WHERE";
        boolean first = true;
        
        if (params.containsKey("name")) {
            baseSql += first ? " name LIKE ?" : " AND name LIKE ?";
            values.add("%" + params.get("name") + "%");
            first = false;
        }
        
        if (params.containsKey("minAge")) {
            baseSql += first ? " age >= ?" : " AND age >= ?";
            values.add(params.get("minAge"));
        }
    }
    
    return jdbcTemplate.query(baseSql, values.toArray(), 
        new BeanPropertyRowMapper<>(User.class));
}

7. 数据库特定功能支持

to_tsvectorto_tsquery 是 PostgreSQL 提供的全文搜索(Full Text Search)功能的核心函数,用于实现高效的文本搜索功能。

基本语法结构:

SELECT * FROM table_name 
WHERE to_tsvector([配置], text_column) @@ to_tsquery([配置], search_query)

使用实例:

public List<User> findUsersWithFullTextSearch(String keyword) {
    // PostgreSQL 的全文检索语法
    String sql = "SELECT * FROM users WHERE to_tsvector(name) @@ to_tsquery(?)";
    return jdbcTemplate.query(sql, new Object[]{keyword}, 
        new BeanPropertyRowMapper<>(User.class));
}

8. 自定义 SQL 生成器

public class SqlBuilder {
    private final StringBuilder sql = new StringBuilder();
    private final List<Object> parameters = new ArrayList<>();
    private boolean whereAdded = false;

    public SqlBuilder select(String columns) {
        sql.append("SELECT ").append(columns);
        return this;
    }

    public SqlBuilder from(String table) {
        sql.append(" FROM ").append(table);
        return this;
    }

    public SqlBuilder where(String condition, Object... params) {
        if (!whereAdded) {
            sql.append(" WHERE ");
            whereAdded = true;
        } else {
            sql.append(" AND ");
        }
        sql.append(condition);
        Collections.addAll(parameters, params);
        return this;
    }

    public SqlBuilder orderBy(String column, boolean ascending) {
        sql.append(" ORDER BY ").append(column)
           .append(ascending ? " ASC" : " DESC");
        return this;
    }

    public String getSql() {
        return sql.toString();
    }

    public Object[] getParameters() {
        return parameters.toArray();
    }
}

// 使用示例
SqlBuilder builder = new SqlBuilder()
    .select("*")
    .from("users")
    .where("age > ?", 18)
    .where("status = ?", "ACTIVE")
    .orderBy("create_time", false);

List<User> users = jdbcTemplate.query(
    builder.getSql(), 
    builder.getParameters(),
    new BeanPropertyRowMapper<>(User.class));

9. 动态批处理大小调整

/**
 * 自适应批处理大小的JdbcTemplate扩展
 */
public class AdaptiveBatchJdbcTemplate extends JdbcTemplate {
    private int currentBatchSize = 100; // 初始批次大小
    private long lastAdjustmentTime = System.currentTimeMillis();

    public AdaptiveBatchJdbcTemplate(DataSource dataSource) {
        super(dataSource);
    }

    /**
     * 执行自适应批处理插入
     * @param dataList 要插入的数据列表
     */
    public <T> void adaptiveBatchInsert(List<T> dataList, BatchOperation<T> operation) {
        int totalSize = dataList.size();
        int processed = 0;
        
        while (processed < totalSize) {
            // 计算当前批次大小
            int actualBatchSize = Math.min(currentBatchSize, totalSize - processed);
            
            // 获取当前批次数据
            List<T> batchData = dataList.subList(processed, processed + actualBatchSize);
            
            // 执行批处理
            long startTime = System.currentTimeMillis();
            int[] result = batchUpdate(
                operation.getSql(),
                new BatchPreparedStatementSetter() {
                    @Override
                    public void setValues(PreparedStatement ps, int i) throws SQLException {
                        operation.setValues(ps, batchData.get(i));
                    }

                    @Override
                    public int getBatchSize() {
                        return batchData.size();
                    }
                });
            
            // 调整批次大小
            long duration = System.currentTimeMillis() - startTime;
            adjustBatchSize(duration, actualBatchSize);
            
            System.out.printf("已处理: %d/%d, 当前批次大小: %d, 耗时: %dms%n",
                processed + actualBatchSize, totalSize, currentBatchSize, duration);
            
            processed += actualBatchSize;
        }
    }

    /**
     * 根据执行时间动态调整批次大小
     */
    private void adjustBatchSize(long duration, int processedSize) {
        long now = System.currentTimeMillis();
        if (now - lastAdjustmentTime > 60000) { // 每分钟最多调整一次
            if (duration > 5000) { // 执行时间过长,减少批次大小
                currentBatchSize = Math.max(10, currentBatchSize / 2);
                System.out.println("【调整】减小批次大小至: " + currentBatchSize);
            } else if (duration < 100 && processedSize == currentBatchSize) { 
                // 执行时间很短且当前批次是满载,增加批次大小
                currentBatchSize = Math.min(1000, currentBatchSize * 2);
                System.out.println("【调整】增大批次大小至: " + currentBatchSize);
            }
            lastAdjustmentTime = now;
        }
    }

    /**
     * 批处理操作接口
     */
    public interface BatchOperation<T> {
        String getSql();
        void setValues(PreparedStatement ps, T item) throws SQLException;
    }
}

//--------------------------------------------------------使用
// 1. 创建自适应批处理模板
AdaptiveBatchJdbcTemplate adaptiveTemplate = 
    new AdaptiveBatchJdbcTemplate(dataSource);

// 2. 准备测试数据
List<User> users = generateTestUsers(5000); // 生成5000个测试用户

// 3. 执行批处理插入
adaptiveTemplate.adaptiveBatchInsert(users, new AdaptiveBatchJdbcTemplate.BatchOperation<User>() {
    @Override
    public String getSql() {
        return "INSERT INTO users(name, age, email) VALUES(?, ?, ?)";
    }

    @Override
    public void setValues(PreparedStatement ps, User user) throws SQLException {
        ps.setString(1, user.getName());
        ps.setInt(2, user.getAge());
        ps.setString(3, user.getEmail());
    }
});

10. 大数据量分批次处理避免内存溢出

/**
 * 大数据量批处理服务示例
 */
public class LargeDataProcessor {

    private final JdbcTemplate jdbcTemplate;
    
    // 批处理大小,可根据实际情况调整
    private static final int DEFAULT_BATCH_SIZE = 1000;

    public LargeDataProcessor(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    /**
     * 处理用户表中的所有数据(分批次)
     * 使用事务确保处理过程的原子性
     */
    @Transactional
    public void processAllUsers() {
        int batchSize = DEFAULT_BATCH_SIZE;
        int offset = 0;
        List<User> batch;
        
        // 记录处理开始时间
        long startTime = System.currentTimeMillis();
        int totalProcessed = 0;
        
        do {
            // 1. 分页查询数据
            batch = fetchUsersBatch(batchSize, offset);
            
            // 2. 处理当前批次数据
            if (!batch.isEmpty()) {
                processUserBatch(batch);
                totalProcessed += batch.size();
            }
            
            // 3. 更新偏移量
            offset += batchSize;
            
        } while (!batch.isEmpty()); // 4. 循环直到没有数据
        
        // 记录处理结果
        long duration = System.currentTimeMillis() - startTime;
        System.out.printf("处理完成!共处理 %d 条记录,耗时 %d 毫秒%n", 
                         totalProcessed, duration);
    }

    /**
     * 分页查询用户数据
     * @param limit 每页大小
     * @param offset 偏移量
     * @return 用户列表
     */
    private List<User> fetchUsersBatch(int limit, int offset) {
        String sql = "SELECT id, name, email, age FROM users ORDER BY id LIMIT ? OFFSET ?";
        
        // 使用BeanPropertyRowMapper自动映射结果到User对象
        return jdbcTemplate.query(
            sql,
            new Object[]{limit, offset},
            new BeanPropertyRowMapper<>(User.class)
        );
    }

    /**
     * 处理单个批次的用户数据
     * @param batch 当前批次的用户列表
     */
    private void processUserBatch(List<User> batch) {
        // 这里可以替换为实际的业务逻辑
        // 示例:简单地打印处理进度
        System.out.printf("正在处理批次,大小: %d, 第一个用户ID: %d%n",
                         batch.size(), batch.get(0).getId());
        
        // 实际业务处理示例:
        // 1. 数据转换
        // 2. 调用外部服务
        // 3. 写入其他系统等
        for (User user : batch) {
            // 处理每个用户的逻辑
            processSingleUser(user);
        }
    }

    /**
     * 处理单个用户
     * @param user 用户对象
     */
    private void processSingleUser(User user) {
        // 示例处理逻辑:
        // 1. 数据校验
        // 2. 业务处理(如:年龄分类)
        // 3. 更新用户(示例)
    }

    /**
     * 根据年龄返回年龄段分类
     */
    private String getAgeGroup(int age) {
        if (age < 18) return "未成年";
        if (age < 30) return "青年";
        if (age < 50) return "中年";
        return "老年";
    }

    /**
     * 更新用户年龄段信息
     */
    private void updateUserAgeGroup(long userId, String ageGroup) {
        String sql = "UPDATE users SET age_group = ? WHERE id = ?";
        jdbcTemplate.update(sql, ageGroup, userId);
    }

    /**
     * 用户实体类
     */
    public static class User {
        private long id;
        private String name;
        private String email;
        private int age;
        private String ageGroup;
        
        // getters and setters
    }
}

11. 结果集处理

  • RowMapper:自定义结果集映射
    List<User> users = jdbcTemplate.query("SELECT * FROM users", (rs, rowNum) -> {
        User user = new User();
        user.setId(rs.getLong("id"));
        user.setName(rs.getString("name"));
        return user;
    });
    
  • ResultSetExtractor:复杂结果集处理
    Map<Long, User> userMap = jdbcTemplate.query("SELECT * FROM users", 
        rs -> {
            Map<Long, User> map = new HashMap<>();
            while (rs.next()) {
                User user = new User();
                user.setId(rs.getLong("id"));
                user.setName(rs.getString("name"));
                map.put(user.getId(), user);
            }
            return map;
        });
    

12. 自定义 RowMapper 复用

public class GenericRowMapper<T> implements RowMapper<T> {
    private final Class<T> targetClass;
    
    public GenericRowMapper(Class<T> targetClass) {
        this.targetClass = targetClass;
    }
    
    @Override
    public T mapRow(ResultSet rs, int rowNum) throws SQLException {
        T obj = targetClass.newInstance();
        ResultSetMetaData metaData = rs.getMetaData();
        int columnCount = metaData.getColumnCount();
        
        for (int i = 1; i <= columnCount; i++) {
            String columnName = metaData.getColumnLabel(i);
            Object value = rs.getObject(i);
            
            try {
                Field field = targetClass.getDeclaredField(columnName);
                field.setAccessible(true);
                field.set(obj, value);
            } catch (NoSuchFieldException e) {
                // 忽略不存在的字段
            }
        }
        
        return obj;
    }
}

// 使用示例
List<User> users = jdbcTemplate.query(
    "SELECT * FROM users", 
    new GenericRowMapper<>(User.class));

二、增删改操作

1. 更新操作

  • update() :执行增删改操作
    jdbcTemplate.update("INSERT INTO users(name, age) VALUES(?, ?)", "张三", 25);
    

2. 批处理操作

  • batchUpdate() :执行批量操作
    public int[] batchInsertUsers(List<User> users) {
        List<Object[]> batchArgs = new ArrayList<>();
        for (User user : users) {
            batchArgs.add(new Object[]{
                user.getName(),
                user.getAge(),
                user.getEmail()
            });
        }
    
        return jdbcTemplate.batchUpdate(
            "INSERT INTO users(name, age, email) VALUES(?, ?, ?)",
            batchArgs);
    }
    

3. 命名参数支持

  • NamedParameterJdbcTemplate:使用命名参数而非位置参数
    Map<String, Object> params = new HashMap<>();
                        params.put("name", "张三");
                        params.put("age", 25);
    namedJdbcTemplate.update("INSERT INTO users(name, age) VALUES(:name, :age)", params);
    

4. 高级批处理

  • 批量插入并返回生成的主键
public int[] batchInsert(List<User> users) {
    return jdbcTemplate.batchUpdate(
        "INSERT INTO users(name, age) VALUES(?, ?)",
        new BatchPreparedStatementSetter() {
            @Override
            public void setValues(PreparedStatement ps, int i) throws SQLException {
                User user = users.get(i);
                ps.setString(1, user.getName());
                ps.setInt(2, user.getAge());
            }
            @Override
            public int getBatchSize() {
                return users.size();
            }
        });
}

5. 自定义类型处理

  • 处理 JSON 等复杂类型
//-------------------自定义类型处理器
jdbcTemplate.update(
    "INSERT INTO products(id, details) VALUES(?, ?::jsonb)", 
    product.getId(), 
    new SqlParameterValue(Types.OTHER, product.getDetailsJson()));
    
//-------------------使用Java对象自动转换
public void insertProductWithObject(Product product) {
    String sql = "INSERT INTO products(id, details) VALUES(?, ?::jsonb)";
    
    // 使用Jackson将对象转为JSON字符串
    ObjectMapper mapper = new ObjectMapper();
    String json = mapper.writeValueAsString(product.getDetails());
    
    jdbcTemplate.update(sql, 
        product.getId(),
        new SqlParameterValue(Types.OTHER, json));
}

//---------------------查询并解析JSON
public Product getProductWithJsonDetails(long id) {
    String sql = "SELECT id, name, details FROM products WHERE id = ?";
    
    return jdbcTemplate.queryForObject(sql, (rs, rowNum) -> {
        Product product = new Product();
        product.setId(rs.getLong("id"));
        product.setName(rs.getString("name"));
        
        // 解析JSON字段
        String json = rs.getString("details");
        ObjectMapper mapper = new ObjectMapper();
        ProductDetails details = mapper.readValue(json, ProductDetails.class);
        product.setDetails(details);
        
        return product;
    }, id);
}

//-------------------------电商产品服务案例
@Repository
public class ProductRepository {
    private final JdbcTemplate jdbcTemplate;
    private final ObjectMapper objectMapper;

    public ProductRepository(JdbcTemplate jdbcTemplate, ObjectMapper objectMapper) {
        this.jdbcTemplate = jdbcTemplate;
        this.objectMapper = objectMapper;
    }

    @Transactional
    public void saveProduct(Product product) {
        String sql = "INSERT INTO products(id, name, price, attributes) VALUES(?, ?, ?, ?::jsonb)";
        
        try {
            String jsonAttributes = objectMapper.writeValueAsString(product.getAttributes());
            
            jdbcTemplate.update(sql,
                product.getId(),
                product.getName(),
                product.getPrice(),
                new SqlParameterValue(Types.OTHER, jsonAttributes));
        } catch (JsonProcessingException e) {
            throw new DataAccessException("Failed to serialize product attributes", e) {};
        }
    }

    public Product findById(long id) {
        String sql = "SELECT id, name, price, attributes FROM products WHERE id = ?";
        
        return jdbcTemplate.queryForObject(sql, (rs, rowNum) -> {
            Product product = new Product();
            product.setId(rs.getLong("id"));
            product.setName(rs.getString("name"));
            product.setPrice(rs.getBigDecimal("price"));
            
            try {
                ProductAttributes attributes = objectMapper.readValue(
                    rs.getString("attributes"), 
                    ProductAttributes.class);
                product.setAttributes(attributes);
            } catch (JsonProcessingException e) {
                throw new DataAccessException("Failed to deserialize attributes", e) {};
            }
            
            return product;
        }, id);
    }

    public List<Product> findByAttribute(String key, String value) {
        String sql = """
            SELECT id, name, price 
            FROM products 
            WHERE attributes @> ?::jsonb
            """;
        
        String jsonCriteria = String.format("{\"%s\": \"%s\"}", key, value);
        
        return jdbcTemplate.query(sql, 
            (rs, rowNum) -> {
                Product product = new Product();
                product.setId(rs.getLong("id"));
                product.setName(rs.getString("name"));
                product.setPrice(rs.getBigDecimal("price"));
                return product;
            },
            jsonCriteria);
    }
}

6. 乐观锁实现(本控制)

@Transactional
public boolean updateWithOptimisticLock(User user) {
    int affected = jdbcTemplate.update(
        "UPDATE users SET name = ?, age = ?, version = version + 1 " +
        "WHERE id = ? AND version = ?",
        user.getName(), user.getAge(), user.getId(), user.getVersion());
    
    if (affected == 0) {
        throw new OptimisticLockingFailureException("数据已被其他事务修改");
    }
    return affected > 0;
}

三、 存储过程操作

在这里插入图片描述

1. 调用存储过程

  • call() :调用存储过程
    jdbcTemplate.call(conn -> {
        CallableStatement   cs = conn.prepareCall("{call proc_name(?, ?)}");
                            cs.setString(1, param1);
                            cs.registerOutParameter(2, Types.INTEGER);
        return cs;
    }, Collections.emptyList());
    

2. 存储过程高级调用

  • 带输出参数的存储过程调用
public int callCalculateUserStatsSafe(int userId) throws DataAccessException {
    try {
        SimpleJdbcCall jdbcCall = new SimpleJdbcCall(jdbcTemplate)
            .withProcedureName("calculate_user_stats")
            // 可选的架构名称(某些数据库需要)
            .withSchemaName("public")
            // 声明返回结果集(如果有)
            .returningResultSet("result_set", 
                new BeanPropertyRowMapper<>(UserStat.class))
            .declareParameters(
                new SqlParameter("user_id", Types.INTEGER),
                new SqlOutParameter("result", Types.INTEGER),
                // 可以声明更多参数
                new SqlOutParameter("message", Types.VARCHAR));
        
        // 执行调用
        Map<String, Object> out = jdbcCall.execute(userId);
        
        // 获取多个输出参数
        int result = (int) out.get("result");
        String message = (String) out.get("message");
        List<UserStat> stats = (List<UserStat>) out.get("result_set");
        
        log.debug("存储过程返回消息: {}", message);
        return result;
        
    } catch (DataAccessException e) {
        log.error("调用存储过程calculate_user_stats失败,用户ID: {}", userId, e);
        throw new ServiceException("统计计算失败", e);
    }
}

四、DDL操作

1. 执行 DDL 语句

  • execute() :执行任意 SQL 语句
    jdbcTemplate.execute("CREATE TABLE users (id INT, name VARCHAR(100))");
    

2. 数据库元数据操作(表结构信息)

/**
 * 打印数据库所有表的结构元数据信息
 * 包括表名和每张表的所有列名及数据类型
 */
public void printTableMetaData() {
    // 使用JdbcTemplate的execute方法执行连接回调
    jdbcTemplate.execute((ConnectionCallback<Void>) conn -> {
        // 1. 获取数据库元数据对象
        DatabaseMetaData metaData = conn.getMetaData();
        
        /*
         * 2. 获取所有表的信息
         * 参数说明:
         * - catalog: 数据库目录名,null表示忽略
         * - schemaPattern: 模式名称模式,null表示忽略
         * - tableNamePattern: 表名模式,"%"表示所有表
         * - types: 表类型数组,这里只查询普通表
         */
        ResultSet tables = metaData.getTables(null, null, "%", new String[]{"TABLE"});
        
        // 3. 遍历所有表
        while (tables.next()) {
            // 获取表名(TABLE_NAME是标准元数据列名)
            String tableName = tables.getString("TABLE_NAME");
            System.out.println("Table: " + tableName);
            
            /*
             * 4. 获取当前表的所有列信息
             * 参数说明:
             * - catalog: 数据库目录名,null表示忽略
             * - schemaPattern: 模式名称模式,null表示忽略
             * - tableNamePattern: 表名,使用当前遍历到的表名
             * - columnNamePattern: 列名模式,null表示所有列
             */
            ResultSet columns = metaData.getColumns(null, null, tableName, null);
            
            // 5. 遍历当前表的所有列
            while (columns.next()) {
                // 打印列名和数据类型(TYPE_NAME是标准元数据列名)
                System.out.println("  Column: " + columns.getString("COLUMN_NAME") + 
                                 " Type: " + columns.getString("TYPE_NAME") +
                                 " Size: " + columns.getInt("COLUMN_SIZE") +
                                 " Nullable: " + (columns.getInt("NULLABLE") == DatabaseMetaData.columnNullable ? "YES" : "NO"));
            }
            
            // 6. 关闭列结果集
            columns.close();
        }
        
        // 7. 关闭表结果集
        tables.close();
        
        // 返回null因为ConnectionCallback需要返回Void类型
        return null;
    });
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Solomon_肖哥弹架构

你的欣赏就是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值