Java深入理解MySQL数据库操作

MySQL作为最流行的开源关系型数据库,与Java的结合在企业级开发中无处不在。作为Java开发者,掌握MySQL的核心操作不仅能提升开发效率,更能深入理解数据持久化的本质。本文将带你系统学习MySQL的基本操作,并通过Java代码实践数据库交互。

一、MySQL基础操作回顾

1.1 数据库与表操作

sql 复制代码
-- 创建数据库
CREATE DATABASE IF NOT EXISTS blog_system 
DEFAULT CHARACTER SET utf8mb4 
COLLATE utf8mb4_unicode_ci;

-- 使用数据库
USE blog_system;

-- 创建用户表
CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) NOT NULL UNIQUE,
    password VARCHAR(255) NOT NULL,
    email VARCHAR(100),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

1.2 CRUD基础操作

sql 复制代码
-- 插入数据
INSERT INTO users (username, password, email) 
VALUES ('zhangsan', 'encrypted_password', 'zhangsan@example.com');

-- 查询数据
SELECT * FROM users WHERE id = 1;
SELECT username, email FROM users WHERE email LIKE '%@example.com';

-- 更新数据
UPDATE users SET email = 'new_email@example.com' WHERE id = 1;

-- 删除数据
DELETE FROM users WHERE id = 1;

二、Java连接MySQL的三种方式

2.1 原生JDBC连接

java 复制代码
import java.sql.*;

public class MySQLBasicConnection {
    private static final String URL = "jdbc:mysql://localhost:3306/blog_system";
    private static final String USER = "root";
    private static final String PASSWORD = "password";
    
    public static void main(String[] args) {
        Connection conn = null;
        Statement stmt = null;
        
        try {
            // 1. 加载驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            
            // 2. 建立连接
            conn = DriverManager.getConnection(URL, USER, PASSWORD);
            System.out.println("数据库连接成功!");
            
            // 3. 创建Statement对象
            stmt = conn.createStatement();
            
            // 4. 执行查询
            String sql = "SELECT * FROM users";
            ResultSet rs = stmt.executeQuery(sql);
            
            // 5. 处理结果集
            while(rs.next()) {
                System.out.println("ID: " + rs.getInt("id"));
                System.out.println("用户名: " + rs.getString("username"));
            }
            
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        } finally {
            // 6. 关闭资源
            try {
                if(stmt != null) stmt.close();
                if(conn != null) conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

2.2 使用连接池(HikariCP)

java 复制代码
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import java.sql.*;

public class ConnectionPoolExample {
    private static HikariDataSource dataSource;
    
    static {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:mysql://localhost:3306/blog_system");
        config.setUsername("root");
        config.setPassword("password");
        config.setMaximumPoolSize(10);
        config.setMinimumIdle(5);
        config.setConnectionTimeout(30000);
        config.setIdleTimeout(600000);
        config.setMaxLifetime(1800000);
        
        dataSource = new HikariDataSource(config);
    }
    
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }
}

2.3 使用PreparedStatement防止SQL注入

java 复制代码
public class PreparedStatementExample {
    
    public User getUserByUsernameAndPassword(String username, String password) {
        String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
        
        try (Connection conn = getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            
            pstmt.setString(1, username);
            pstmt.setString(2, password);
            
            ResultSet rs = pstmt.executeQuery();
            
            if (rs.next()) {
                User user = new User();
                user.setId(rs.getInt("id"));
                user.setUsername(rs.getString("username"));
                user.setEmail(rs.getString("email"));
                return user;
            }
            
        } catch (SQLException e) {
            e.printStackTrace();
        }
        
        return null;
    }
    
    public void batchInsertUsers(List<User> users) {
        String sql = "INSERT INTO users (username, password, email) VALUES (?, ?, ?)";
        
        try (Connection conn = getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            
            for (User user : users) {
                pstmt.setString(1, user.getUsername());
                pstmt.setString(2, user.getPassword());
                pstmt.setString(3, user.getEmail());
                pstmt.addBatch();
            }
            
            pstmt.executeBatch();
            
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

三、事务管理与ACID特性

java 复制代码
public class TransactionExample {
    
    public boolean transferMoney(int fromUserId, int toUserId, double amount) {
        Connection conn = null;
        PreparedStatement pstmt1 = null;
        PreparedStatement pstmt2 = null;
        
        try {
            conn = getConnection();
            // 关闭自动提交,开启事务
            conn.setAutoCommit(false);
            
            // 扣除转出账户金额
            String sql1 = "UPDATE accounts SET balance = balance - ? WHERE user_id = ? AND balance >= ?";
            pstmt1 = conn.prepareStatement(sql1);
            pstmt1.setDouble(1, amount);
            pstmt1.setInt(2, fromUserId);
            pstmt1.setDouble(3, amount);
            
            int rows1 = pstmt1.executeUpdate();
            if (rows1 == 0) {
                throw new SQLException("转出账户余额不足");
            }
            
            // 增加转入账户金额
            String sql2 = "UPDATE accounts SET balance = balance + ? WHERE user_id = ?";
            pstmt2 = conn.prepareStatement(sql2);
            pstmt2.setDouble(1, amount);
            pstmt2.setInt(2, toUserId);
            
            pstmt2.executeUpdate();
            
            // 提交事务
            conn.commit();
            return true;
            
        } catch (SQLException e) {
            // 回滚事务
            if (conn != null) {
                try {
                    conn.rollback();
                } catch (SQLException ex) {
                    ex.printStackTrace();
                }
            }
            e.printStackTrace();
            return false;
        } finally {
            // 恢复自动提交并关闭连接
            try {
                if (conn != null) {
                    conn.setAutoCommit(true);
                    conn.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

四、结果集处理与RowMapper模式

java 复制代码
public class ResultSetHandler {
    
    // 传统方式处理ResultSet
    public List<User> getAllUsersTraditional() {
        List<User> users = new ArrayList<>();
        String sql = "SELECT * FROM users";
        
        try (Connection conn = getConnection();
             Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery(sql)) {
            
            while (rs.next()) {
                User user = new User();
                user.setId(rs.getInt("id"));
                user.setUsername(rs.getString("username"));
                user.setEmail(rs.getString("email"));
                user.setCreatedAt(rs.getTimestamp("created_at"));
                user.setUpdatedAt(rs.getTimestamp("updated_at"));
                users.add(user);
            }
            
        } catch (SQLException e) {
            e.printStackTrace();
        }
        
        return users;
    }
    
    // 使用RowMapper模式
    @FunctionalInterface
    public interface RowMapper<T> {
        T mapRow(ResultSet rs) throws SQLException;
    }
    
    public <T> List<T> query(String sql, RowMapper<T> rowMapper, Object... params) {
        List<T> results = new ArrayList<>();
        
        try (Connection conn = getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            
            for (int i = 0; i < params.length; i++) {
                pstmt.setObject(i + 1, params[i]);
            }
            
            try (ResultSet rs = pstmt.executeQuery()) {
                while (rs.next()) {
                    results.add(rowMapper.mapRow(rs));
                }
            }
            
        } catch (SQLException e) {
            e.printStackTrace();
        }
        
        return results;
    }
    
    // 使用示例
    public List<User> getAllUsers() {
        String sql = "SELECT * FROM users";
        return query(sql, rs -> {
            User user = new User();
            user.setId(rs.getInt("id"));
            user.setUsername(rs.getString("username"));
            user.setEmail(rs.getString("email"));
            return user;
        });
    }
}

五、数据库连接最佳实践

5.1 使用try-with-resources自动关闭资源

java 复制代码
public class DatabaseUtil {
    
    public static void executeQuery(String sql) {
        // try-with-resources会自动关闭Connection、Statement和ResultSet
        try (Connection conn = getConnection();
             Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery(sql)) {
            
            while (rs.next()) {
                // 处理结果
            }
            
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

5.2 配置文件管理数据库连接

java 复制代码
// database.properties
// db.url=jdbc:mysql://localhost:3306/blog_system
// db.username=root
// db.password=password
// db.pool.size=10

public class ConfigManager {
    private static Properties props = new Properties();
    
    static {
        try (InputStream input = ConfigManager.class
                .getClassLoader()
                .getResourceAsStream("database.properties")) {
            props.load(input);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    public static String getProperty(String key) {
        return props.getProperty(key);
    }
}

六、性能优化技巧

6.1 批量操作提升性能

java 复制代码
public class BatchOperationExample {
    
    public void batchInsertWithTransaction(List<User> users) {
        String sql = "INSERT INTO users (username, password, email) VALUES (?, ?, ?)";
        
        try (Connection conn = getConnection()) {
            conn.setAutoCommit(false);
            
            try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
                for (User user : users) {
                    pstmt.setString(1, user.getUsername());
                    pstmt.setString(2, user.getPassword());
                    pstmt.setString(3, user.getEmail());
                    pstmt.addBatch();
                    
                    // 每1000条执行一次批量提交
                    if (users.indexOf(user) % 1000 == 0) {
                        pstmt.executeBatch();
                    }
                }
                
                pstmt.executeBatch();
                conn.commit();
                
            } catch (SQLException e) {
                conn.rollback();
                throw e;
            }
            
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

6.2 使用连接池参数调优

java 复制代码
public class OptimizedConnectionPool {
    
    public static HikariDataSource createOptimizedDataSource() {
        HikariConfig config = new HikariConfig();
        
        // 核心配置
        config.setJdbcUrl(ConfigManager.getProperty("db.url"));
        config.setUsername(ConfigManager.getProperty("db.username"));
        config.setPassword(ConfigManager.getProperty("db.password"));
        
        // 性能优化配置
        config.addDataSourceProperty("cachePrepStmts", "true");
        config.addDataSourceProperty("prepStmtCacheSize", "250");
        config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
        config.addDataSourceProperty("useServerPrepStmts", "true");
        config.addDataSourceProperty("useLocalSessionState", "true");
        config.addDataSourceProperty("rewriteBatchedStatements", "true");
        config.addDataSourceProperty("cacheResultSetMetadata", "true");
        config.addDataSourceProperty("cacheServerConfiguration", "true");
        config.addDataSourceProperty("elideSetAutoCommits", "true");
        config.addDataSourceProperty("maintainTimeStats", "false");
        
        return new HikariDataSource(config);
    }
}

七、实战:简单的博客系统DAO实现

java 复制代码
// User实体类
public class User {
    private Integer id;
    private String username;
    private String password;
    private String email;
    private Timestamp createdAt;
    private Timestamp updatedAt;
    
    // 构造方法、getter和setter省略
}

// UserDAO接口
public interface UserDAO {
    User findById(Integer id);
    List<User> findAll();
    Integer insert(User user);
    boolean update(User user);
    boolean delete(Integer id);
    User findByUsername(String username);
}

// UserDAO实现
public class UserDAOImpl implements UserDAO {
    
    @Override
    public User findById(Integer id) {
        String sql = "SELECT * FROM users WHERE id = ?";
        
        try (Connection conn = getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            
            pstmt.setInt(1, id);
            ResultSet rs = pstmt.executeQuery();
            
            if (rs.next()) {
                return mapUser(rs);
            }
            
        } catch (SQLException e) {
            e.printStackTrace();
        }
        
        return null;
    }
    
    @Override
    public Integer insert(User user) {
        String sql = "INSERT INTO users (username, password, email) VALUES (?, ?, ?)";
        
        try (Connection conn = getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql, 
                     Statement.RETURN_GENERATED_KEYS)) {
            
            pstmt.setString(1, user.getUsername());
            pstmt.setString(2, user.getPassword());
            pstmt.setString(3, user.getEmail());
            
            int affectedRows = pstmt.executeUpdate();
            
            if (affectedRows == 0) {
                throw new SQLException("创建用户失败");
            }
            
            try (ResultSet generatedKeys = pstmt.getGeneratedKeys()) {
                if (generatedKeys.next()) {
                    return generatedKeys.getInt(1);
                } else {
                    throw new SQLException("获取生成ID失败");
                }
            }
            
        } catch (SQLException e) {
            e.printStackTrace();
            return null;
        }
    }
    
    private User mapUser(ResultSet rs) throws SQLException {
        User user = new User();
        user.setId(rs.getInt("id"));
        user.setUsername(rs.getString("username"));
        user.setPassword(rs.getString("password"));
        user.setEmail(rs.getString("email"));
        user.setCreatedAt(rs.getTimestamp("created_at"));
        user.setUpdatedAt(rs.getTimestamp("updated_at"));
        return user;
    }
}

总结

通过本文的学习,我们掌握了:

  1. MySQL基础操作:从DDL到DML的核心语句

  2. Java连接MySQL的多种方式:原生JDBC、连接池、PreparedStatement

  3. 事务管理:确保数据操作的ACID特性

  4. 结果集处理:传统方式与RowMapper模式

  5. 最佳实践:资源管理、配置优化

  6. 性能优化:批量操作、连接池调优

  7. 实战应用:完整的DAO层实现

下一步学习建议

  1. 学习ORM框架:如MyBatis、Hibernate

  2. 掌握数据库设计原则:规范化、索引优化

  3. 学习高级特性:存储过程、触发器、视图

  4. 探索分库分表:应对大数据量场景

  5. 了解数据库监控:慢查询分析、性能调优

希望这篇博客能帮助你在Java与MySQL的学习道路上更进一步。数据库操作是后端开发的核心技能,熟练掌握这些基础将为职业生涯奠定坚实的基础。
参考资料:MySQL官方文档、JDBC API文档


原创声明:本文为原创技术博客,转载请注明出处。欢迎在评论区交流讨论!

相关推荐
NE_STOP2 小时前
SpringBoot集成shiro
java
RemainderTime2 小时前
从零搭建Spring Boot3.x生产级单体脚手架项目(JDK17 + Nacos + JWT + Docker)
java·spring boot·架构
黯叶2 小时前
基于 Docker+Docker-Compose 的 SpringBoot 项目标准化部署(外置 application-prod.yml 配置方案)
java·spring boot·redis·docker
say_fall2 小时前
泛型编程基石:C++ 模板从入门到熟练
java·开发语言·c++·编辑器·visual studio
代码笔耕2 小时前
写了几年 Java,我发现很多人其实一直在用“高级 C 语言”写代码
java·后端·架构
txinyu的博客2 小时前
结合游戏场景解析UDP可靠性问题
java·开发语言·c++·网络协议·游戏·udp
一路向北North2 小时前
springboot基础(85): validator验证器
java·spring boot·后端
1.14(java)2 小时前
掌握数据库约束:确保数据精准可靠
java·数据库·mysql·数据库约束
Codeking__2 小时前
Redis——value的数据类型与单线程工作模型
java·数据库·redis