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文档


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

相关推荐
枫叶落雨2226 小时前
ShardingSphere 介绍
java
素玥6 小时前
实训5 python连接mysql数据库
数据库·python·mysql
花花鱼6 小时前
Spring Security 与 Spring MVC
java·spring·mvc
言慢行善7 小时前
sqlserver模糊查询问题
java·数据库·sqlserver
专吃海绵宝宝菠萝屋的派大星7 小时前
使用Dify对接自己开发的mcp
java·服务器·前端
大数据新鸟7 小时前
操作系统之虚拟内存
java·服务器·网络
Tong Z7 小时前
常见的限流算法和实现原理
java·开发语言
喵了几个咪7 小时前
如何在 Superset Docker 容器中安装 MySQL 驱动
mysql·docker·容器·superset
凭君语未可7 小时前
Java 中的实现类是什么
java·开发语言
He少年7 小时前
【基础知识、Skill、Rules和MCP案例介绍】
java·前端·python