贪吃蛇与服务器MySQL连接版(JDBC应用)

写在最前

由于疫情原因,学习也很懈怠,这个事情三天打鱼两天晒网也做了一个月。得反思一下自己…

功能描述

在原有贪吃蛇的基础上,当游戏结束之后,在控制台提示输入玩家名字,如果输入的是“查询”,则将之前所有玩家的成绩打印在控制台上,如果不是,则把贪吃蛇游戏分数、玩家名字、游戏时间上传到服务器的数据库(MySQL)。

(至于我为什么要在控制台上实现这个功能,而不是在写一个窗口实现查询和上传成绩呢?我也这么想过,试过一段时间,可是Java的swing我真的玩不太明白,干脆简单的来,原理都是一样的!)

视频介绍

Java贪吃蛇数据库连接版

素材准备

贪吃蛇的实现参考我之前博客,此次完全在之前的基础上添加功能,游戏主体代码不变:贪吃蛇传送门

服务器是用电脑虚拟机下的ubuntu(之前用过centos7,坑很多,最后放弃了,还是ubuntu方便一点)

值得注意的是在安装ubuntu后要选择好阿里的下载服务器,否则速度慢的不行(我原来等过一下午下载MySQL,现在想想傻得不行…):解决ubuntu下载慢的问题

解决这个问题以后,咱们就得要完成ubuntu下的MySQL安装:下载安装传送门

这样我们就完成了一个用电脑作为服务器的搭建,下面就需要完成贪吃蛇与服务器数据之前的交换。

思路介绍

MySQL是用SQL语句实现对数据库的所有操作,什么是SQL语句?

结构化查询语言(Structured Query Language)简称SQL,结构化查询语言是一种数据库查询和程序设计语言,用于存取数据以及查询、更新和管理关系数据库系统;sql 语句就是对数据库进行操作的一种语言。(在我的理解是和Linux命令差不多功能的语言)

我们会用到哪些SQL语句?

因为是实现记录的上传和查询。自然就是对数据库的增和查。(如需详细学习SQL语句,请看最后的资源下载板块,下载MySQL笔记来学习MySQL)

用Java怎么操作数据库?

Java对数据库的操作叫做JDBC,有一系列的类帮助我们完成对数据库的操作(如需详细学习,可以下载最后的资源下载板块,来下载JDBC笔记)

所以我们应该怎么实现我们这个功能?
分为三个步骤:
1,加载JDBC驱动
2,获取与数据库的链接
3,执行相关SQL语句
4,处理数据库的返回结果(如果有)

代码实现

JDBCUtils

这是我自己写的类,功能是完成对数据库连接,资源的释放等一些与数据库相关的操作,将其封装起来,代码更具有可读性。

值得说一下的是:将数据库的URL(URL怎么写传送门),用户名密码可以放在一个配置文件当中,以后要更改只需要修改配置文件就可以了,而读取配置文件有两种方法:

  • 1、Properties方法:Properties文件是java中很常用的一种配置文件,文件后缀为“.properties”,属文本文件,文件的内容格式是“键=值”的格式,可以用“#”作为注释,java编程中用到的地方很多,运用配置文件,可以便于java深层次的解耦。
  • 2、类加载器的方法:ClassLoader 类加载器

    因为本文没有采用这种放啊,所以详细介绍不多说,想学习的进行传送门:类加载器传送门


    实现方法是:
            ClassLoader classLoader = JDBCUtils.class.getClassLoader();
           URL res  = classLoader.getResource("jdbc.properties");
            String path = res.getPath();//获取路径
            System.out.println(path);
           pro.load(new FileReader(path));
                 /**
             * 注意!!!!!!
             * 利用类加载器不能使用的原因是文件夹有中文字符,导致乱码
             */

另外在对数据库进行操作的时候,会使用到很多个类,这些类要释放资源,所以在JDBCUtils写一个对资源管理的方法很有必要。
使用多态的形式释放资源

public static void close(Statement stmt, Connection conn) {
        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 释放资源
     *
     * @param stmt
     * @param conn
     */
    public static void close(ResultSet rs, Statement stmt, Connection conn) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

JDBCUtils完整代码。

package util;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;

/**
 * JDBC工具类
 */
public class JDBCUtils {
    private static String url;
    private static String user;
    private static String password;
    private static String driver;

    /**
     * 文件的读取,只需要读取一次即可拿到这些值。使用静态代码块
     */
    static {
        //读取资源文件,获取值。
        try {
            //1. 创建Properties集合类。
            Properties pro = new Properties();
            /**
             * Properties文件是java中很常用的一种配置文件,文件后缀为“.properties”,属文本文件,
             * 文件的内容格式是“键=值”的格式,可以用“#”作为注释,java编程中用到的地方很多,运用配置文件,可以便于java深层次的解耦。
             */
            //获取src路径下的文件的方式--->ClassLoader 类加载器
//            ClassLoader classLoader = JDBCUtils.class.getClassLoader();
//            URL res  = classLoader.getResource("jdbc.properties");
//            String path = res.getPath();//获取路径
//            System.out.println(path);
//            pro.load(new FileReader(path));
            /**
             * 注意!!!!!!
             * 利用类加载器不能使用的原因是文件夹有中文字符,导致乱码
             */
            pro.load(new FileReader("src/jdbc.properties"));
            //3. 获取数据,赋值
            url = pro.getProperty("url");
            user = pro.getProperty("user");
            password = pro.getProperty("password");
            driver = pro.getProperty("driver");
            //4. 注册驱动
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取连接
     *
     * @return 连接对象
     */
    public static Connection getConnection() {
        try {
            return DriverManager.getConnection(url, user, password);
        } catch (SQLException throwables) {
            System.out.println("获取连接失败!");
            throwables.printStackTrace();
            return null;
        }
    }

    /**
     * 释放资源
     *
     * @param stmt
     * @param conn
     */
    public static void close(Statement stmt, Connection conn) {
        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 释放资源
     *
     * @param stmt
     * @param conn
     */
    public static void close(ResultSet rs, Statement stmt, Connection conn) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

Connection类

首先,要加载JDBC的驱动(最后资源下载板块会提供),要注意的是,要选择好MySQL版本和驱动版本。这里使用MySQL8实验。

先上代码(看不懂没关系)

public static Connection getConnection()  {
        try {
            return DriverManager.getConnection(url, user, password);
        } catch (SQLException throwables) {
            System.out.println("获取连接失败!");
            throwables.printStackTrace();
            return null;
        }
    }

我们先写一个方法来获取到数据库的链接对象Connection,该对象的数据库能够提供描述其表,其支持的SQL语法,其存储过程,此连接的功能等的信息。

DriverManager.getConnection是尝试建立与给定数据库URL的连接。三个参数分别是jdbc的URL,数据库的用户名,数据库的密码。 DriverManager尝试从一组已注册的JDBC驱动程序中选择适当的驱动程序。 连接成功将返回Connection对象。

PreparedStatement类

这个类是干什么的?

PreparedStatement类详解传送门

SQL语句已预编译并存储在一个PreparedStatement对象中。 然后可以使用该对象多次有效地执行此语句。

怎么获取这个类?

我们将已经获取好的Connection对象下的Connection.prepareStatement​(String sql)方法创建一个PreparedStatement对象,用于将参数化的SQL语句发送到数据库。

怎么执行SQL语句呢?

我们将已经获取好的PreparedStatement对象下的PreparedStatement.executeUpdate()方法可以执行增删改的SQL语句。这样我们就完成了对数据库的添加代码。

 public static void insert(String name, int sore) {
        Connection con = null;//利用JDBC工具类获得连接对象
        PreparedStatement psta = null;
        try {
            String insert_sql = "INSERT INTO record ( name ,sore,insert_time)  VALUES (?,?,CURRENT_TIMESTAMP )";
            con = JDBCUtils.getConnection();
//            psta = con.createStatement();//用于执行静态SQL语句并返回其生成的结果的对象。
            /**
             使用prepareStatement而不是原来的Statement目的是解决sql注入问题。
             */
            con.setAutoCommit(false);//打开事务
            psta = con.prepareStatement(insert_sql);//用于执行静态SQL语句并返回其生成的结果的对象。
//            int res = psta.executeUpdate(insert_sql
            psta.setString(1, name);//给sql第一个?赋值
            psta.setInt(2, sore);//给sql第二个?赋值
            int res = psta.executeUpdate();

            /**
             *  在prepareStatement里面执行sql,先给sql的参数赋值(字符串里面的?)
             *    然后执行这条语句(注意这条语句没有参数)
             */
            /*
            如果执行成功,会返回影响的行数。
            为0则数据库没有进行任何变化。
             */
            if (res > 0) {
                System.out.println("添加成功!");
            } else {
                System.out.println("添加失败!");
            }
            con.commit();//如果没有异常的发生,证明操作正常,则提交事务,改变数据库的值
        } catch (Exception throwables) {
            if (con != null) {
                try {
                    con.rollback();
                    /**
                     * 如果发生了异常,则需要把事务回滚,防止数据库意外发生
                     * 需要注意的是,在catch里面,要选择Exception,只要出现了异常就要进行回滚操作
                     */
                    System.out.println("添加失败!");
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            throwables.printStackTrace();
        } finally {
            JDBCUtils.close(psta, con);//释放资源
        }
    }

这样我们就完成了对数据库的增添功能,那么查找怎么办?

查找和添加思路一样,都是获取对象,执行SQL语句,唯一不一样的是,查询会返回一个结果集,而增添返回就是影响的行数。所以查询你就要求我们对结果集进行操作。

这个结果集是什么?

这个结果集是ResultSet类,是PreparedStatement下的executeQuery()方法的放回结果,这个结果集类似于一个指针,每次指向一行结果,只对一行结果进行操作,如果换行,需要在使用方法。具体内容请传送门:ResultSet类详解传送门

这样就是查询方法的完整代码。

 public static void select() {
        ResultSet result = null;
        Connection con = null;
        PreparedStatement psta = null;
        try {
            String select_sql = "SELECT * FROM record";
            con = JDBCUtils.getConnection();
            psta = con.prepareStatement(select_sql);//用于执行静态SQL语句并返回其生成的结果的对象。
            result = psta.executeQuery();
            while (result.next()) {
                System.out.println(result.getString(1) + "     " + result.getInt(2) + "     " + result.getString(3));
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            JDBCUtils.close(result, psta, con);
        }
    }
}

资源下载

代码:(代码当中MySQLl的IP地址为空,驱动在lib文件夹下)
链接:https://pan.baidu.com/s/1s_Wesv-w4DSZcmtIEh33gg
提取码:btaa

MySQL笔记:点击下载

JDBC笔记:点击下载

  • 6
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值