觉得不错(JDBC)

搬运自bilibili

概念

JDBC:Java DataBase Connectivity,Java 数据库连接,Java语言操作数据库
JDBC的本质:其实就是官方(SUN公司)定义的一套操作所有关系型数据库的规则,也就是接口。各个数据库厂商去实现这套接口,提供数据库驱动jar包。我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。

快速入门

步骤:
1. 导入驱动jar包
2. 注册驱动
3 .获取数据库连接对象 Connection
4. 定义sql
5. 获取执行sql语句的对象 Statement
6. 执行sql,接收返回的结果
7. 处理结果
8. 释放资源
下面是一个一段家娃栗子:

package cn.itcast.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;

public class JDBCDemo {
    public static void main(String[] args) throws Exception {

        //1.导入驱动jar包
        //2.注册驱动
        Class.forName("com.mysql.cj.jdbc.Driver");
        //3.获取数据库连接对象
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/xuyuwei?characterEncoding=utf8&serverTimezone=Asia/Shanghai","root","root");
        //4.定义sql语句
        String sql = "INSERT INTO account VALUES (NULL,'张三',1000);";
        //5.获取执行sql的对象,Statement
        Statement stmt = conn.createStatement();
        //6.执行对象
        int count = stmt.executeUpdate(sql);
        //7.处理结果
        System.out.println(count);
        //8.释放资源
        stmt.close();
        conn.close();
    }
}

/**
 * 在JDBCDemo中的写法会有一些问题,比如在某处程序出错停止后,后面的.close()方法没办法执行
 * 造成内存泄漏,下面将写一个修改的版本
 * */
package cn.itcast.jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

public class JDBCDemo2 {
    public static void main(String[] args) {

        Connection conn = null;
        Statement stmt = null;
        try {
            //1.注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            //2.通过DriverManager获取连接对象
            conn = DriverManager.getConnection("jdbc:mysql:///xuyuwei?serverTimezone=Asia/Shanghai", "root", "123456");
            //3.编写sql语句
            String sql = "CREATE TABLE stu (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(20),class VARCHAR(20))";
            //4.获取执行sql的对象
            stmt = conn.createStatement();
            //5.执行sql
            int returnNum = stmt.executeUpdate(sql);//当执行的是DDL语句的时候返回值为0
            //6.显示执行结果
            System.out.println(returnNum);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //7.关闭连接

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



看到上面那么多类那么多对象,早就懵圈了吧,下面来港一下各个类和对象的作用:

1.DriverManager:驱动管理对象

*功能:
	1.注册驱动:告诉程序该使用哪一个数据库驱动jar
	public static void registerDriver(Driver driver);//DriverManager中的静态方法
	
	所以咋注册(调用这个方法)呢?
	答:Class.forName("com.mysql.cj.jdbc.Driver");
		使用反射机制加载Driver类
		
	为毛使用上面的代码就可以注册呢?
	答:Driver类被加载时会执行其中的静态代码块,查看Driver类的静态块:
static {
	try {
		DriverManager.registerDriver(new Driver());
	} catch (SQLException var1) {
		throw new RuntimeException("Can't register driver!");
	}
}
	*注意:mysql5之后的驱动jar包可以忽略注册的步骤
2.获取数据库连接
	*方法:public static Connection getConnection(String url,
                                  String user,
                                  String password);
       *参数:
       	*url:指定连接的路径
			*语法:jdbc:mysql://ip地址(域名):端口号/数据库名称?编码方式&时区  //?之后的可以不设置
	*user:用户名
	*password:密码

2.Connection:数据库连接对象

1.功能:
	1.获取执行sql的对象(Statement的对象)
		*Statement createStatement() 
		*PreparedStatement prepareStatement(String sql) 
	2.管理事务
		*开启事务:void setAutoCommit(boolean autoCommit) //当autoCommit=false时,开启事务(关闭自动提交)
		*提交事务:commit()
		*回滚事务:rollback()

3.Statement:执行sql语句的对象

1.功能:执行sql
	1.boolean execute(String sql) //执行给定的SQL语句,这可能会返回多个结果。
	2.int executeUpdate(String sql) //执行DML(INSERT,UPDATE,DELETE)语句、
	  DDL(CREATE,ALTER,DROP)语句。一般很少执行DDL语句。在执行DML语句时,返回
	  值:sql语句执行后影响的行数,可以通过这个返回值来判断DML语句是否执行成功,
	  返回值>0时代表执行成功。
	3.ResultSet executeQuery(String sql) //执行给定的SQL语句,该语句返回单个 ResultSet对象(看下面)。 

4.ResultSet:结果集对象,封装查询到的结果

方法:
	1.next()方法:使游标向下移动一行
	2.getXxx(参数):获取表中的数据
		*Xxx代表数据类型,比方:getInt(),getString()
		*参数:
			1.int:代表该条查询记录的列号,从1开始。如getInt(1);
			2.String:代表列名称。如:getString(name); //name是表中字段的名称
/**
 * 这里要举例使用JDBC的查询功能,这里只是举个栗子,并不是最标准的写法。
 * 要关注的就是另一个比较重要的类——ResultSet
 * */

//3.编写sql语句
String sql = "SELECT * FROM employee";
//4.获取执行sql的对象
stmt = conn.createStatement();
//5.执行sql
rs = stmt.executeQuery(sql);//当执行的是DDL语句的时候返回值为0
//6.显示执行结果
rs.next(); //指针初始位置是在表头位置,调用.nest()方法使指针下移到第一条记录(指针不下移会报异常)
int id = rs.getInt(1);
String name = rs.getString(2);
int age = rs.getInt(3);
System.out.println("员工编号:"+id+"\n员工姓名"+name+"\n员工年龄是"+age);

//7.关闭连接
if(rs != null){
    try {
        rs.close();
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

注意.next()方法,它有两个功能:
	1.使得指针向下移动一行
	2.返回一个boolean类型的返回值
		true:该行是有记录的
		false:改行没有记录了(位于最后一行记录之后)
因此,上面的java代码是比较腊鸡的写法:步骤6可以改进一下:
//6.显示执行结果
            while(rs.next()){ //打印所有的记录
                int id = rs.getInt(1);
                String name = rs.getString(2);
                int age = rs.getInt(3);
                System.out.println("员工编号:"+id+"\n员工姓名:"+name+"\n员工年龄:"+age);
                System.out.println("==============");
            }

5.PreparedStatement
  PreparedStatement是一个执行动态sql的接口。为毛要PreparedStatement?因为它更灵活,还可以有效的防止sql注入攻击。
  百度一下啥是sql注入:SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。
  举个小栗子,假如有一个用户名密码登录系统,要用户名密码一致才能登录。

//伪代码
String sql = "select * from table where userid = "+userid+"and password ="+ password;
if (statement.executeQuery(sql).next()){
	System.out.println("登录成功");
}else{
	System.out.println("登录失败");
}

如果password = “ ‘abc’ or ‘a’ = ‘a’ ”
则查询的结果为全表。判断处就会打印登录成功。

因此,静态的sql语句确实会有安全问题。下面说一下PreparedStatement的用法:

String sql = "select * from table where userid = ? and password = ?";
PreparedStatement pstmt	= conn.preparedstatement(sql);
pstmt.setString(1,userid);
pstmt.setString(2,password);
ResultSet rs = pstmt.executeQuery();

问号为占位符,setXxx(占位符下标,传递参数)。占位符下标从1开始。

建立JDBCUtil(使得代码更简洁)
新建一个类,取名JDBCTool。主要完成:

  • 注册驱动
    Class.forname("");

  • 获取Connection对象
    DriverManager.getConnection(url,user,password);

  • 关闭数据库连接
    xxx.close();


下面将详细介绍下这个类的作用:

  • 首先为了后期不修改代码,数据库连接中的driverurluserpassword应当写在配置文件中;
    步骤如下:
    1. 在src目录下新建一个file,命名为jdbc.properties,在配置文件中写入:
driver = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://localhost:3306/xuyuwei?characterEncoding=utf8&serverTimezone=Asia/Shanghai
user = root
password = root

2.读取配置文件的方法:

//1.创建properties集合类
Properties pro = new Properties();
//2.加载配置文件,其中path为jdbc.properties的绝对文件路径
pro.load(new FileReader(path));
//3.读取配置文件中的内容
String url = pro.getProperty("url");
String user = pro.getProperty("user");
String password = pro.getProperty("password");
String driver = pro.getProperty("driver");

这么做有个问题,就是读取配置文件的路径不是动态的,如果路径换了,那就gg了。
因此需要动态的获取路径。那咋整呢?
这就需要用到ClassLoader这个类了。
步骤:
 1.使用反射机制获取JDBCTool类的类对象,通过类对象获取类加载器ClassLoader

ClassLoader cl = JDBCTool.class.getClassLoader();//获取ClassLoader对象 
//此处的类只要是该项目中的类就可以,比如可以将JDBCTool替换为另一个类JDBCDemo

 2.使用类加载器获取文件的路径

URL res = cl.getResource("cn/itcast/jdbc/jdbc.properties");//获取配置文件的url
//cl默认的根目录是src目录,后面getResource方法中输入properties文件的路径,上面展示
//是将properties文件放在jdbc包中

 3.将路径对象变为String类型

String path = res.getPath();//将URL对象转换为字符串

至此,配置文件路径的动态链接就完成了。
上述操作只需要执行一次,因此,驱动注册和获取配置文件属性的操作放在类的静态块中。

  • 获取Connection对象:

话不多说直接上代码:

/**
 * 获取Connection对象
 * @return conn对象
  */
 public static Connection getConnection(){
        Connection conn = null;
        try {
            conn = DriverManager.getConnection(url,user,password);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return conn;
    }
  • 关闭数据库连接

关闭有两种情况

  1. 如果是执行的操作语句那就关闭Statement和Connection。
  2. 如果是执行的查询语句那就关闭ResultSet,Statement和Connection。

这里就需要写两个方法,来执行不同的情况。来用用java多态:

/**
     * 执行操作语句时调用
     * @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 rs
     * @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();
            }
        }
    }
}

好了JDBCTool类的功能就这么多。
.

数据库连接池

标准: 由sun公司制定的标准,具体实现由第三方厂家来完成。
标准接口:javax.sql.DataSource
接口方法getConnection()来获取连接,close()方法归还连接。

实现技术:
①C3P0 :数据库连接池技术
②Druid :数据库连接池技术,由阿里巴巴公司提供


使用C3P0的方法

  1. 首先需要导入jar包:①c3p0-0.9.5.5.jar ②mchange-commons-java-0.2.19.jar(记得先导入第三方驱动jar包)
  2. 配置文件:c3p0.properties 或者 c3p0-config.xml。自己写个xml放到src目录下就可以了。
    c3p0-config.xml:
<c3p0-config>

    <!--使用默认的配置读取参数-->
    <default-config>
        <property name = "driverClass">com.mysql.cj.jdbc.Driver</property>
        <!---->
        <property name = "jdbcUrl">jdbc:mysql://localhost:3306/xuyuwei?characterEncoding=utf8&amp;serverTimezone=Asia/Shanghai</property>
        <property name = "user">root</property>
        <property name = "password">root</property>

        <!--连接池参数-->
        <!--初始化申请的连接数量-->
        <property name = "initialPoolSize">5</property>
        <!--最大连接数量-->
        <property name = "maxPoolSize">10</property>
        <!--超时时间-->
        <property name = "checkoutTimeout">3000</property>
    </default-config>

    <!--使用其他的配置读取参数-->
    <named-config name = "otherc3p0">
        <property name = "driverClass">com.mysql.cj.jdbc.Driver</property>
        <property name = "jdbcUrl">jdbc:mysql://localhost:3306/xuyuwei?characterEncoding=utf8&amp;serverTimezone=Asia/Shanghai</property>
        <property name = "user">root</property>
        <property name = "password">root</property>

        <!--连接池参数-->
        <property name = "initialPoolSize">5</property>
        <property name = "maxPoolSize">7</property>
        <property name = "checkoutTimeout">3000</property>
    </named-config>
</c3p0-config>

这里解释一下配置文件:
maxPoolSize:连接池最多能容纳多少连接
checkoutTimeout:当获取连接失败(达到最大连接了),静默多长时间后抛出异常。

  1. 创建连接池对象:CombopooledDataSource
  2. 获取连接:使用getConnection()方法获取连接
import java.sql.Connection;
import java.sql.SQLException;

public class C3P0Demo1 {
    public static void main(String[] args) throws SQLException {
        //1.创建连接池对象
        DataSource ds = new ComboPooledDataSource();//使用默认配置
//        DataSource ds = new ComboPooledDataSource("otherc3p0");//使用自定义配置
        //2.获取连接
        Connection conn = ds.getConnection();
    }
}

使用Druid数据库连接池

  1. 第一步还是导包:druid-1.1.9.jar
  2. 定义配置文件:
    使用properties配置文件,可以放在任意路径,任意名称。需手动导入配置。
  3. 通过一个工厂类DruidDataSourceFactory来获取数据库连接池对象。
  4. 获取连接getConnection()。
import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties;

public class DruidDemo1 {
    public static void main(String[] args) throws Exception {

        //1.加载配置文件
            //1.1将配置文件读入字节流
        InputStream is = DruidDemo1.class.getClassLoader().getResourceAsStream("cn/itcast/druid/druid.properties");
        //1.2新建一个Properties对象
        Properties pro = new Properties();
            //1.3将获取的字节流附给pro对象
        pro.load(is);

        //2.通过工厂类来得到
        DataSource ds = new DruidDataSourceFactory().createDataSource(pro);

        //3.获取连接
        Connection conn = ds.getConnection();
        System.out.println(conn);
    }
}

编写工具类
为了使得代码更规范更整洁,编写工具类。
首先要明确工具类JDBCUtils的作用是什么。

  1. 创建数据库连接池。(需要一加载就能连接,那就用static块)
  2. 返回数据库连接对象(通过类直接使用,那就用static方法)
  3. 返回数据库连接池对象
  4. 关闭ResultSet和Statement,归还数据库连接。

明确了这四个功能,工具类就能完成了。

import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class JDBCUtils {
    //定义成员变量
    private static DataSource ds;

    static {
        try {
            //加载配置文件
            Properties pro = new Properties();
            pro.load(JDBCUtils.class.getClassLoader().getResourceAsStream("cn/itcast/datasource/druid/druid.properties"));

            //新建线程池对象
            ds = new DruidDataSourceFactory().createDataSource(pro);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获得数据库连接
     * @return Connection
     * @throws SQLException
     */
    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }

    /**
     * 关闭Statement和归还数据库连接Connection
     * @param stmt
     * @param conn
     */
    public static void close(Statement stmt,Connection conn){
        //关闭Statement
        if(stmt != null){
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        //归还连接
        if(conn != null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 关闭ResultSet,Statement和归还连接Connection
     * @param rs
     * @param stmt
     * @param conn
     */
    public static void close(ResultSet rs, Statement stmt, Connection conn) {
        //关闭ResultSet
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        close(stmt, conn);
    }

    /**
     * 获取连接池
     * @return
     */
    public static DataSource getDataSource(){
        return ds;
    }
}

工具类写好之后,就可以开开心心的使用工具类来操作数据库了。
下面写一个insert语句来示范一下。

import cn.itcast.datasource.utils.JDBCUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class SqlPoolTest {
    //使用数据库连接池完成一个添加记录的操作
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement pstmt = null;

        try {
            //获取连接
            conn = JDBCUtils.getConnection();
            //定义sql语句
            String sql = "insert into account values(null,?,?)";
            //获得Statement对象
            pstmt = conn.prepareStatement(sql);
            pstmt.setString(1,"莫文蔚");
            pstmt.setDouble(2,2341);
            //执行sql
            int count = pstmt.executeUpdate();
            System.out.println(count);

        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //关闭开启对象
            JDBCUtils.close(pstmt,conn);
        }
    }
}

还有一个牛逼的工具:SpringJDBC

  SpringJDBC提供了一个JdbcTemplate对象,用于简化开发。
  为什么说简化呢?因为Spring对JDBC进行了封装,使用使只需要创建JdbcTemplate对象,然后就执行sql语句。不用去管创建连接和关闭连接的操作。
  JdbcTemplate需要传入一个DataSource,之后就可以用JdbcTemplate对象进行CURD操作。

  JdbcTemplate的常用方法:
1.update():执行增删改操作(DML)

2.queryForMap():将结果集封装为map集合,查询结果只能为一条

Map<String,Object> map = template.queryForMap(sql,1,2,3);//1,2,3是pstmt的?,?,?

3.queryForList():将结果集封装为list集合,将每一条结果封装为一个map,再将所有的map装载在一个list中

List<Map<String,Object>> list = template.queryForList(sql,1,2,3);//1,2,3是pstmt的?,?,?

4.query():将结果封装为JavaBean对象(常用)

//Emp是自定义的一个JavaBean类
List<Emp> list = template.query(sql,new RowMapper<Emp>(){
	@override
	public Emp mapRow(ResultSet rs,int i)throw SQLException{
		Emp emp = new Emp();
		emp.setId(rs.getInt("id"));
		emp.setName(rs.getString("name"));
		emp.setBalance(rs.getDouble("balance"))
		return null;
	}
});

//也可以使用Spring封装好的RowMapper类-->BeanPropertyRowMapper
List<Emp> list = template.query(sql,new BeanPropertyRowMapper<Emp>(Emp.class));

5.queryForObject():将结果封装为对象,一般用于聚合函数的查询封装。

String sql = "select count(id) from emp";
Long total = template.queryForObject(sql,Long.class);

下面说说咋用:

  1. 要用丝不润首先还是得导包。
    commons-logging-1.2.jar
    spring-beans-4.3.9.RELEASE.jar
    spring-core-4.3.9.RELEASE.jar
    spring-jdbc-4.3.9.RELEASE.jar
    spring-tx-4.3.9.RELEASE.jar
  2. 创建JdbcTemplate对象
  3. 执行sql

就是这么简单几步。

import cn.itcast.datasource.utils.JDBCUtils;
import org.springframework.jdbc.core.JdbcTemplate;

public class JdbcTemplateDemo1 {
    public static void main(String[] args) {
        //获得JdbcTemplate对象
        JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
        //编写sql语句
        String sql = "update account set balance = ? where name = ? ";
        //调用方法
        int count = template.update(sql, 0, "莫文蔚");
        System.out.println(count);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值