Java学习_JDBC

一.JDBC 连接数据库

  1. JDBC的本质

    JDBC本质是一个java类,能够实现sun公司提供的一套接口规范。如
    java.sql.Driver
    java.sql.Connection
    java.sql.Satatement
    
  2. JDBC连接数据库的7大步骤

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.ResultSet;
    import java.sql.Statement;
    
    /**
     * 七大步骤
     *  1)导包驱动包
     *  2)注册驱动--加载驱动类
     *  3)获取数据库的连接对象java.sql.Connection
     *  4)准备sql语句
     *  5)通过Connection连接对象获取数据库的执行对象
     *  6)执行sql语句
     *  7)释放资源
     */
    public class JdbcCRUD {
        public static void main(String[] args) throws Exception{
            // 1)导包驱动包
            // 2)注册驱动--加载驱动类
            // 3)获取数据库的连接对象java.sql.Connection
            Connection conn = 
              DriverManager.getConnection("jdbc:mysql://localhost:3306/test",
                    "root",
                    "root");
            // 4)准备sql语句
            String sql = "select * from stu";
            // 5)通过Connection连接对象获取数据库的执行对象
            Statement stmt = conn.createStatement();
            // 6)执行sql语句
            ResultSet res = stmt.executeQuery(sql);
            //输出
            while (res.next()){
                System.out.println(res.getInt("id")+
                        res.getString("name")+res.getString("sex") + 
                                   res.getString("address")
                        );
            }
            // 7)释放资源
            res.close();
            stmt.close();
            conn.close();
    
        }
    }
    
    
  3. 封装工具类

    import java.io.IOException;
    import java.io.InputStream;
    import java.sql.*;
    import java.util.Properties;
    
    public class JdbcUtils {
    
        //成员变量声明三个变量
        private static String url = null ;
        private static String user = null ;
        private static String password = null ;
        private static String driverClass = null ;
    
        //模拟 驱动jar包---Driver驱动类---提供静态代码块
        static{
            try {
                //想办法获取这些参数---->提供配置文件  后缀名.properties---->放在
                //src下面
                //1)读取配置文件内容
                InputStream inputStream = JdbcUtils.class.getClassLoader()
                        .getResourceAsStream("jdbc.properties");
                //2)创建一个属性集合列表Properties
                Properties prop = new Properties() ;
                //System.out.println(prop) ;//测试 ---肯定空列表
                //3)将1)获取资源文件的输入流对象---加载到属性集合列表中
                prop.load(inputStream);
               // System.out.println(prop) ; //测试--->有属性列表内容
                //4)通过key获取value
                driverClass = prop.getProperty("driverClass");
                url = prop.getProperty("url") ;
                user = prop.getProperty("user") ;
                password = prop.getProperty("password") ;
                //5)加载驱动类
                Class.forName(driverClass) ;
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    
    
        private  JdbcUtils(){}
    
    
        /**
         * 获取数据库的连接对象
         * @return
         */
        public static Connection getConnection(){
    
            try {
                //需要驱动管理DriverManager获取连接对象
                Connection connection = DriverManager.getConnection(url, user, password);//获取这三个参数的内容
                return connection ;
    
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            return  null ;
        }
    
        /**
         * 释放资源,针对DQL语句操作释放的相关资源对象
         * @param rs
         * @param stmt
         * @param conn
         */
        public static void close(ResultSet rs,Statement stmt,Connection conn){
           if(rs!=null){
               try {
                   rs.close();
               } catch (SQLException throwables) {
                   throwables.printStackTrace();
               }
           }
            if(stmt!=null){
                try {
                    stmt.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if(conn!=null){
                try {
                    conn.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }
        /**
         * 释放资源,针对DDL语句,DML语句
         * @param stmt
         * @param conn
         */
        public static void close(Statement stmt,Connection conn){
          close(null,stmt,conn);
        }
    }
    
  4. PreparedStatement预编译对象的操作步骤

    PreparedStatement原生的写法
    1)注册驱动
    2)获取数据库的连接对象
    3)准备参数化sql语句,使用占位符号?
    4)通过数据库的连接对象 获取预编译对象,同时将sql发送给数据库,(参数类型,第几个参数)都会存储在预编译对象中
    5)给参数赋值
    6)执行预编译的sql
    7)释放资源
    
    
    1.创建数据库连接对象
    Connection con = DruidJdbcUtils.getConnnection();
    
    2.准备参数化SQL语句
    String sql = "select * from table_name where id = ?";
    3.获取SQL预编译执行对象,同时发送参数化SQL到数据库进行编译
    PrepareStatement stmt = conn.preparedStatemnet(sql);
    4.参数赋值
    stmt.setInt(1,5);
    5.执行查询
    ResultSet re = stmt.executeQuery();
    6.遍历结果集
    while(re.next()){
    	re.getInt("id");
    }
    
    
  5. Statement和PreparedStatement预编译的区别

    1. 效率方面
    	Statement对象:每次书写一条sql就需要通过Statment将sql语句发送给数据库,效率低;同时,会对数据库造成很大压力。
    	PrepareStatement对象:将一条参数化的sql语句发送给数据库,进行预编译,将编译结果存储在预编译对象中,下一次直接赋值,且可以赋值多次,发送一次sql,执行不同的参数
    2. 安全方面
    	Statement对象:发送的sql语句存在字符串拼接,会出现安全问题(SQL注入,恶意攻击数据库,造成安全漏洞)
    	PrepareStatement对象:参数化的sql语句不存在字符串拼接,有效防止SQL注入,开发中使用PreparedStatement来对数据库CRUD,比Statement安全。
    
  6. 连接池

    1. 原生写法的弊端
        1)会造成Connection连接对象浪费
        2)频繁在创建数据库连接对象,执行效率低
    
    2. 通过连接池解决原生写法的弊端
    	sun公司提供一个接口 javax.sql.DataSource代表
    	DriverManger驱动管理类,是一个物理数据源工厂!
    
        通过连接池的方式实现javax. sql. DataSource接口---里
        面的getConnection()方法
            1)这个jar包--数据厂商提供druid版本号.jar
            2)准备连接池的配置文件-->配置相关连接池的参数
        connectionPool连接池存放一些 初始化连接对象的数量以及
        最大连接数量
    
  7. 连接池的作用

    1. 资源重复利用
    	使用连接池,避免了频繁的创建连接对象,使用完毕关闭后,造成资源销毁大
    2. 提高系统的响应速度
    	在程序启动时,提前准备了足够的连接对象,储存在连接池中,当用户访问较多时,可以直接冲连接池中取连接对象,执行速度快.
    3. 控制连接对象
    	多个连接对象被多个线程在同一时刻使用的时候,连接池中对连接对象进行申请,利用,释放,归还连接池等待下一次使用
    
  8. 加入连接池技术的JdbcUtils工具类的优化

    1. 引入ThreadLocal
    	模拟线程场景,每一个线程都是用自己的连接对
    	象!ThreadLocal<T>
    
        ThreadLocal <Connecion>
        public ThreadLocal()
        public void set(T value) :将指定的值绑定在当前线程
        上(绑定)
        public void remove() : 解绑,某个线程使用完毕之后,连
        接对象归还连接池
        之后,需要将连接对象从线程中解绑!
        public T get() : 获取当前线程中的执行的值
    
        用法:
        创建一个ThreadLocal<类型> Connection模拟线程场景!
        在DuridJdbcUtils提供一个静态方法----->
        getConnection()--->Connection
        1)从当前线程中获取连接对象,
        2)判断如果当前这个连接对象==null
        3)需要从连接池中获取连接对象,绑定在当前线程上
        4)返回从连接池中连接对象
        提供一个静态方法-- coss--->关闭资源 
        当将Connection连接对象close之后,归还连接池中,当前线程
        应该将绑定
        连接对象,进行解绑!
    

    加入连接池的工具类优化:

    DruidJdbcUtils工具类代码实现

    import com.alibaba.druid.pool.DruidDataSourceFactory;
    
    import javax.sql.DataSource;
    import java.io.IOException;
    import java.io.InputStream;
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.util.Properties;
    
    /**
     * 加入Druid连接池的工具类
     *
     * 1)现在目的就创建数据源--javax.sql.DataSource接口--->通过DruidDataSourceFactory创建数据源
     * 2)模拟真实场景
     */
    public class DruidJdbcUtils {
    
        //声明数据源
        private static DataSource ds  = null ;
    
    
        //模拟线程 :每一个线程使用自己的Conneciton
        private static ThreadLocal<Connection> t1 = new ThreadLocal<>();
    
        //构造方法私有化,外界类不能new
        private DruidJdbcUtils(){}
    
        //静态代码块
        static{
            try {
                //当前工具类一加载,读取src下面的druid.properties配置文件
                InputStream inputStream = 
                    DruidJdbcUtils.class.getClassLoader().
                        getResourceAsStream("配置文件.properties");
                //创建属性集合列表,将配置文件资源输入流加载属性集合列表中
                Properties prop = new Properties() ;
                prop.load(inputStream) ;
                //通过DruidDataSourceFactory创建DataSource对象----
                >DruidDataSource具体子实现类
                给ds重写赋值
                ds = DruidDataSourceFactory.createDataSource(prop);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 获取数据源,就是将配置文件的内容加载到了DataSource
         * @return
         */
        public static DataSource getDataSource(){
            return ds ;
        }
    
        /**
         * 从连接池中获取连接对象  ---->首先需要创建DataSource接口对象
         * @return
         */
        public static Connection getConnection(){
            try {
                //1)从当前线程获取Conection
                Connection conn = t1.get();
                if(conn==null){
                    //2)当前线程中没有连接对象
                    //需要从DataSource连接池获取连接对象
                    conn  = ds.getConnection();
                    //3)将当前连接对象绑定在当前线程上
                    t1.set(conn);
                }
                return conn ;
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
    
            return  null ;
        }
    
        //释放资源 针对DQL语句
        public static void close(ResultSet rs, PreparedStatement ps 
                                 ,Connection conn){
            if(rs!=null){
                try {
                    rs.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if(ps!=null){
                try {
                    ps.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if(conn!=null){
                try {
                    conn.close(); 
                    //归还连接池中
                    //需要从当前线程ThreadLocal进行解绑
                    t1.remove();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }
    
        /**
         * 针对DDL或者DML语句
         * @param ps
         * @param conn
         */
        public static void close( PreparedStatement ps ,Connection conn){
           close(null,ps,conn);
        }
    
        //开启事务  ---控制事务:连接对象必须使用同一个!
        public static void setAutoCommit() throws SQLException {
            //从连接池获取连接对象
            Connection conn = getConnection();
            //手动提交
            conn.setAutoCommit(false) ; 
        }
    
        //回滚事务
        public static void rollBackAndClose() throws SQLException {
            Connection conn = getConnection();
            //回滚
            conn.rollback(); 
            conn.close();
            //解绑
            t1.remove(); 
        }
        //提交事务
        public static void commitAndClose() throws SQLException {
            Connection conn = getConnection();
            //提交事务
            conn.commit(); 
            conn.close();
            //解绑
            t1.remove(); 
        }
    }
    
    

二. 单元测试

  1. 步骤

    1)导包junit的核心包以及依赖包
    2)提供单元测试方法----->定义一个功能,没有返回值,没有参数,在方法上面@Test标记,它是一个单元测试方法
    3)@Before,标记的方法是在单元测试方法之前先执行----->初始化的操作
    4)@After,标记的方法是在用单元测试执行之后执行---->释放资源
    
  2. 单元测试代码示例

    import org.junit.Before;
    import org.junit.Test;
    
    import java.sql.SQLException;
    import java.util.List;
    
    @SuppressWarnings("all")
    public class DbUtilsTest {
        private productDao pd;
        @Before
        public void init(){
           pd =  new ProductImpl();
        }
    
        @Test
        public void testFindAll() throws SQLException {
            List<Product> list = pd.findAll();
            for(Product product:list){
                System.out.println(product);
            }
        }
    
        @Test
        public void testAdd() throws SQLException {
            pd.add(new Product(6,"热水袋",8,"温暖你的一切"));
        }
    
        @Test
        public void testDeleteById() throws SQLException {
            pd.deleteById(1);
        }
    
        @Test
        public void testUpdateById() throws SQLException {
            pd.updateByid(new Product(2,"华为手机",3000,"充电5分钟,通话两小时"));
        }
    
        @Test
        public void testFindByid() throws SQLException {
            Product pr = pd.findById(6);
            System.out.println(pr);
        }
    
        @Test
        public void testFindByName() throws SQLException {
            List<Product> list = pd.findByName("%华%");
            for (Product product : list) {
                System.out.println(product);
            }
        }
    
    }
    
    
  3. 注意:单元测试中不能有键盘录入

四. dbUtils的使用

  1. 使用

    1. 导入核心包 commons-dbutils-1.6/7.jar
    2. 创建核心执行器:QueryRunner
    	QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource());
    3. 准备SQL
    	String sql = "select password from admin where username = ?";
    4. 执行SQL
    	//查询
    	Admin admin = qr.query(sql, new BeanHandler<>(Admin.class),username);
    	//更新
    	int count = qr.update(sql,name);
    

五. JDBC控制事务

通过sql指令的方式控制事务
1)开启事务:start transaction ;
2)执行多个sqL语句/或者多张表的sqL--添加/删除/修改
3)如果有问题,回滚事务rollback;
没有问题,提交事务最终 commit ;


JDBC方式控制事务
java.sql.Connection:
void setAutoCommit (boolean autoCommit) throws sQLException 设置提交模式
参数为false,表示禁用自动提交;为true,默认就是自动提交
void rollback() throws sQLException
事务回滚,撤销之前的所有更新操作; (前提必须处于手动提交
void commit() throws sQLException 提交事务, 将数据永久保存!

六. 完整demo

  1. 项目结构

    在这里插入图片描述

  2. 实体类

    public class Product {
        private int id;
        private String pname;
        private int pprice;
        private String pdesc;
    
        public Product() {
        }
    
        public Product(int id, String pname, int pprice, String pdesc) {
            this.id = id;
            this.pname = pname;
            this.pprice = pprice;
            this.pdesc = pdesc;
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getPname() {
            return pname;
        }
    
        public void setPname(String pname) {
            this.pname = pname;
        }
    
        public int getPprice() {
            return pprice;
        }
    
        public void setPprice(int pprice) {
            this.pprice = pprice;
        }
    
        public String getPdesc() {
            return pdesc;
        }
    
        public void setPdesc(String pdesc) {
            this.pdesc = pdesc;
        }
    
        @Override
        public String toString() {
            return "product{" +
                    "id=" + id +
                    ", pname='" + pname + '\'' +
                    ", pprice=" + pprice +
                    ", pdesc='" + pdesc + '\'' +
                    '}';
        }
    }
    
    
  3. 接口

    import java.sql.SQLException;
    import java.util.List;
    
    public interface productDao {
        /**
         * 查询所有员工
         * @return
         */
        List<Product>  findAll() throws SQLException;
    
        /**
         * 添加商品数据
         */
        void add(Product product) throws SQLException;
    
        /**
         * 通过商品id删除
         */
        void deleteById(int id) throws SQLException;
    
        /**
         * 更新商品信息
         */
        void updateByid(Product product) throws SQLException;
    
        /**
         * 通过ID查询
         */
        Product findById(int id) throws SQLException;
    
        /**
         * 模糊查询
         */
        List<Product> findByName(String name) throws SQLException;
    
    }
    
    
  4. 实现类

    import org.apache.commons.dbutils.QueryRunner;
    import org.apache.commons.dbutils.handlers.BeanHandler;
    import org.apache.commons.dbutils.handlers.BeanListHandler;
    import org.junit.Before;
    
    import javax.sql.DataSource;
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.util.ArrayList;
    import java.util.List;
    
    public class ProductImpl implements productDao {
        static DataSource dataSource = DruidJdbcUtils.getDataSource();
        static QueryRunner qr = new QueryRunner(dataSource);
    
        @Override
        public List<Product> findAll() throws SQLException {
            String sql = "select * from product";
            List<Product> list = qr.query(sql, new BeanListHandler<>(Product.class));
            return list;
        }
    
        @Override
        public void add(Product product) throws SQLException {
            String sql = "insert into product(id,pname,pprice,pdesc) values (?,?,?,?)";
            //获取预编译执行对象
            int count = qr.update(sql, product.getId(), product.getPname(), product.getPprice(), product.getPdesc());
            System.out.println("插入成功,共影响行数为:"+count);
    
        }
    
        @Override
        public void deleteById(int id) throws SQLException {
    
            //准备SQL
            String sql = "delete from product where id = ?";
            int count = qr.update(sql,id);
            System.out.println("删除成功,共影响行数为:"+count);
        }
    
        @Override
        public void updateByid(Product product) throws SQLException {
            //准备SQL
            String sql = "update product set pname = ?,pprice = ?,pdesc = ? where id = ?";
            int count = qr.update(sql,product.getPname(),product.getPprice(),product.getPdesc(),product.getId());
            System.out.println("更新成功,共影响行数为:"+count);
        }
    
        @Override
        public Product findById(int id) throws SQLException {
            //准备SQL
            String sql = "select * from product where id = ?";
            Product product = qr.query(sql, new BeanHandler<>(Product.class),id);
    
            return product;
        }
    
        @Override
        public List<Product> findByName(String name) throws SQLException {
            //准备SQL
            String sql = "select * from product where pname like ?";
            List<Product> list = qr.query(sql, new BeanListHandler<>(Product.class), name);
            return list;
        }
    
    }
    
    
  5. 测试类

    import org.junit.Before;
    import org.junit.Test;
    
    import java.sql.SQLException;
    import java.util.List;
    
    @SuppressWarnings("all")
    public class DbUtilsTest {
        private productDao pd;
        @Before
        public void init(){
           pd =  new ProductImpl();
        }
    
        @Test
        public void testFindAll() throws SQLException {
            List<Product> list = pd.findAll();
            for(Product product:list){
                System.out.println(product);
            }
        }
    
        @Test
        public void testAdd() throws SQLException {
            pd.add(new Product(6,"热水袋",8,"温暖你的一切"));
        }
    
        @Test
        public void testDeleteById() throws SQLException {
            pd.deleteById(1);
        }
    
        @Test
        public void testUpdateById() throws SQLException {
            pd.updateByid(new Product(2,"华为手机",3000,"充电5分钟,通话两小时"));
        }
    
        @Test
        public void testFindByid() throws SQLException {
            Product pr = pd.findById(6);
            System.out.println(pr);
        }
    
        @Test
        public void testFindByName() throws SQLException {
            List<Product> list = pd.findByName("%华%");
            for (Product product : list) {
                System.out.println(product);
            }
        }
    }
    
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Java SQLite3 JDBC是一种用于在Java应用程序中连接和操作SQLite3数据库的API。 SQLite是一种轻量级的嵌入式数据库引擎,适用于许多小型和中小型项目。它使用简单且易于理解的SQL语法,并将所有数据库的内容存储在单个文件中,这使得SQLite非常适合于需要在单个机器上进行本地存储和处理的应用程序。 Java提供了许多用于与各种数据库进行交互的API,其中包括SQLite3数据库JDBCJava Database Connectivity)是Java提供的用于连接和操作各种数据库的标准API。 使用Java SQLite3 JDBC,开发人员可以轻松地在Java应用程序中实现与SQLite3数据库的连接和交互。首先,需要下载并导入SQLite JDBC驱动程序,然后在代码中使用合适的连接字符串(包括数据库文件路径)连接到SQLite3数据库。一旦连接成功,就可以执行SQL语句来执行数据库的各种操作,例如插入、查询、更新和删除数据。JDBC还提供了一些方法来处理数据库事务和处理结果集。 Java SQLite3 JDBC的优势包括:易于学习和使用,无需额外的数据库服务器,占用资源少,性能良好。它是开源和免费的,适用于各种小型和中型项目。 总之,Java SQLite3 JDBC是一个有助于在Java应用程序中连接和操作SQLite3数据库的API。它提供了简单且直观的方法来实现与SQLite3数据库的连接和交互,并且是一个流行和广泛使用的工具。 ### 回答2: Java SQLite3 JDBC 是一个用于在 Java 程序中连接和操作 SQLite3 数据库的 API。它提供了一组用于在 Java 程序中执行 SQL 查询和更新的类和接口。 Java SQLite3 JDBC 提供了一种简便的方式来连接 SQLite3 数据库。通过 JDBC 驱动程序,我们可以在 Java 程序中访问 SQLite3 数据库。我们可以执行各种 SQL 查询,如 SELECT、INSERT、UPDATE 和 DELETE,并可以获取结果集以及对数据库进行事务处理。 使用 Java SQLite3 JDBC,我们首先需要下载 SQLite3 JDBC 驱动程序,并将其添加到我们的项目中。然后,我们可以通过调用 `Class.forName("org.sqlite.JDBC")` 加载驱动程序类。接下来,我们可以使用 `DriverManager.getConnection()` 方法来连接到 SQLite3 数据库,并传递数据库的连接字符串作为参数。 一旦我们成功连接到数据库,我们可以使用 `Connection` 对象创建 `Statement` 或 `PreparedStatement` 对象,并使用它们来执行 SQL 查询。通过 `executeQuery()` 方法执行 SELECT 查询,并使用 `ResultSet` 对象来处理查询结果。对于 INSERT、UPDATE 或 DELETE 操作,我们可以使用 `executeUpdate()` 方法来执行 SQL 命令,并获取受影响的行数。 在完成数据库操作后,我们应该关闭 `ResultSet`、`Statement` 和 `Connection` 对象,以释放资源并保证数据的一致性。 总而言之,Java SQLite3 JDBC 提供了一个方便的方式来连接和操作 SQLite3 数据库。它可以在 Java 程序中执行各种 SQL 查询和更新,并提供了一组类和接口来处理数据库连接和事务处理。它使得在 Java 程序中使用 SQLite3 数据库变得简单和高效。 ### 回答3: Java sqlite3 jdbc是一种用于在Java编程语言中操作SQLite数据库的API。SQLite是一种轻量级、嵌入式的关系型数据库,它在本地文件中存储数据,无需配置额外的服务器。 通过Java sqlite3 jdbc,我们可以很方便地连接SQLite数据库,并对其进行增删改查的操作。首先,我们需要通过JDBC驱动程序连接到SQLite数据库。可以通过添加相关的JAR文件或在Maven中添加依赖项来获取相应的驱动。然后,我们可以使用jdbc连接字符串指定数据库的位置和其他相关参数。 一旦连接成功,我们可以使用java.sql包提供的接口和方法执行SQL语句,如创建表、插入数据、更新数据和查询数据等。我们可以使用PreparedStatement类来预编译SQL语句,提高执行效率。还可以使用ResultSet类来处理查询结果。 在使用Java sqlite3 jdbc时,我们需要注意以下几点:首先,要保证数据库文件的路径正确,并具有读写权限。其次,为了防止SQL注入攻击,我们应该使用参数化查询,而不是直接拼接SQL语句。另外,为了提高性能,可以使用事务来批量执行一系列SQL语句。 总的来说,Java sqlite3 jdbc为开发人员提供了一个方便、易用的工具,使他们能够轻松地在Java程序中操作SQLite数据库。通过这个API,我们可以实现对SQLite数据库的各种操作,从而满足应用程序对数据的存储和检索需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值