后端开发——JDBC的学习(三)

本篇继续对JDBC进行总结:

①通过Service层与Dao层实现转账的练习;

②重点:由于每次使用连接就手动创建连接,用完后就销毁,这样会导致资源浪费,因此引入连接池,练习连接池的使用;

③实现一个工具类,不用每次都手写获取连接以及配置数据库要素等,并且对工具类进行优化;然后使用连接池以及工具类对前部分转账部分的练习进行优化;

④对于工具类只封装好了1.注册驱动2.创建连接8.回收资源,因此3.4.5.6.7.这五步没有完成;因此需要用高级应用层封装对这五步进行封装;基本每一个数据表都有一个对应的DAO接口以及其实现类,对其进行增删改查,但是这些操作重复性很高,所以可以抽取出公共的代码,然后给这些DAO的实现类可以抽取一个公共的父类,称为BaseDao; 对于查询操作需要用executeQuery,增删改操作需要用executeUpdate,所以增删改一体,查询一体;

后面会继续更新Mybatis简化JDBC的操作;

以下代码可以直接复制到idea中运行,整体的位置如下:(注意导入druid以及jdbc jar包)

代码一:转账的练习

包含两部分代码,一部分是Service层一部分是Dao层;

package data_test7;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;

//TODO 此类是对bank表的一些操作;
public class BankDao {
    //account 加钱的账号,money:加钱的金额;这里需要设计jdbc因为是对数据库中的表中数据进行操作:
    public  void add(String account,int money,Connection connection)throws Exception{
        //此处就不需要再创建链接了,为了保证同一个事务,需要使用一样的连接才行;
        //Class.forName("com.mysql.cj.jdbc.Driver");
        //Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/jdbc_test", "root", "dir99");
        String sql="update t_bank set money=money+? where account=?;";
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        preparedStatement.setObject(1,money);
        preparedStatement.setObject(2,account);
        int i = preparedStatement.executeUpdate();
        preparedStatement.close();
        //connection.close();
        System.out.println("加钱成功!");
    }
    public  void sub(String account,int money,Connection connection)throws Exception{
        //此处就不需要再创建链接了,为了保证同一个事务,需要使用一样的连接才行;
        //Class.forName("com.mysql.cj.jdbc.Driver");
        //Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/jdbc_test", "root", "dir99");
        String sql="update t_bank set money=money-? where account=?;";
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        preparedStatement.setObject(1,money);
        preparedStatement.setObject(2,account);
        int i = preparedStatement.executeUpdate();
        preparedStatement.close();
        //connection.close();
        System.out.println("扣钱成功!");

    }
}
package data_test7;

import org.junit.Test;

import java.sql.Connection;
import java.sql.DriverManager;

//TODO 转账测试:
//TODO 银行卡业务方法,调用Dao中的方法;
public class BankService {
    @Test
    public void start() throws Exception {
        //hello给hi转账500块:
        transfer("hi","hello",500);
    }

    public void transfer(String addAccount,String subAccount,int money) throws Exception {
        BankDao bankDao=new BankDao();
        //注意这种方法不准确,因为当一个账户money为零的时候,再运行加钱还是成功,扣钱会报错。
        // 因此需要统一为一个事务,这个事务包括加钱和扣钱;注意一个事务最基本的要求就是必须是同一个连接对象,connection;
        //TODO 需要加上注册驱动和创建连接以及try-catch并且需要关闭自动提交事务,这样加钱和扣钱就是同一个事务;
        Class.forName("com.mysql.cj.jdbc.Driver");
        Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/jdbc_test", "root", "dir99");
        try{
            //设置不自动提交事务
            connection.setAutoCommit(false);
            bankDao.add(addAccount,money,connection);//此处需要再传入connection连接;
            bankDao.sub(subAccount,money,connection);
            //事务提交:
            connection.commit();
        }catch(Exception e){
            //事务回滚:
            connection.rollback();
            //抛出异常:
            throw e;
        }finally {
            connection.close();
        }
        //TODO 正常就提交事务,出现异常就回滚到原来的那样,防止扣钱失败,但是加钱成功类似的错误;
        //TODO 总结:事务是添加到业务方法中的;利用try-catch代码块,开始事务和提交事务以及事务回滚;将connection传入dao层即可,dao只负责使用,不用close;


    }
}

代码二:连接池的使用:

package data_test8;//TODO 数据库连接池:每次使用连接就创建然后销毁的话,会比较浪费资源,因此使用的时候可以在连接池中直接获取,使用完后再放回到连接池中:
// Druid连接池的使用:

import com.alibaba.druid.pool.DruidDataSource;
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.SQLException;
import java.util.Properties;

public class DruidUsepart {
    //硬编码方式:
    //直接使用代码设置连接池连接参数方式!
    //1.创建一个druid连接池对象
    //2.设置连接池参数:【必须|非必须】
    //3.获取连接[通用方法,所有连接都一样]
    //4.回收连接
    public void testHard() throws Exception {
        //连接池对象:
        DruidDataSource dataSource=new DruidDataSource();
        //设置参数:
        //必须设置的参数:
        dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/jdbc_test");
        dataSource.setUsername("root");
        dataSource.setPassword("dir99");
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");//帮助注册驱动和创建连接;
        //非必须的参数:
        dataSource.setInitialSize(5);//初始化连接的数量;
        dataSource.setMaxActive(10);//最大数量
        //获取链接:
        Connection connection=dataSource.getConnection();
        //数据库操作
        connection.close();
    }
    public void testSoft() throws Exception {
        //软编码方式:
        //通过读取外部的配置文件的方法实例化druid连接池对象;
        //1.读取配置文件 Properties
        Properties properties=new Properties();
        InputStream resourceAsStream = DruidUsepart.class.getClassLoader().getResourceAsStream("druid.properties");
        properties.load(resourceAsStream);
        //2.使用连接池工具类的工厂模式创建连接池;
        DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
        Connection connection=dataSource.getConnection();
        //数据库操作
        connection.close();
    }
}
//TODO 每次使用连接都这样重新设置比较麻烦,因此想将他们封装到工具类中,每次想使用调用那个类即可;

代码三:工具类的实现以及优化:

普通版:

package data_test8;

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.SQLException;
import java.util.Properties;

//TODO 工具类1.0版本,内部包含一个连接池对象,并且对外提供获取连接和回收连接的方法;
//TODO 工具类中的方法一般设置为静态的,方便外部调用;
/*实现内容:
属性:连接池对象只能实例化一次 实现方法:单例模式或者static代码块(全局只调用一次)
方法:对外提供链接的方法,回收外部传入连接方法
 */
public class jdbc_utils1 {
    private static DataSource dataSource=null;
    static{
        Properties properties=new Properties();
        InputStream resourceAsStream = jdbc_utils1.class.getClassLoader().getResourceAsStream("druid.properties");
        try {
            properties.load(resourceAsStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            dataSource= DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //对外提供获取连接方法:
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }
    //回收方法:
    public static void freeConnection(Connection connection) throws SQLException {
        connection.close();
    }


}

优化后:

package data_test8;
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.SQLException;
import java.util.Properties;
//TODO 对于第一个版本的工具类有缺陷,就是在不同方法中调用getconnection方法,返回的是新的连接,并不是一样的连接;
//TODO 利用线程本地变量存储连接信息,确保一个线程的多个方法获取同一个连接connection;
// 优点:实务操作的时候,service和dao 属于同一个线程,不用再传递参数了,大家都可以调用getConnection方法自动获取的是同一个连接;

public class jdbc_util2 {
    private static DataSource dataSource=null;
    private static ThreadLocal<Connection>tl=new ThreadLocal<>();

    static{
        Properties properties=new Properties();
        InputStream resourceAsStream = jdbc_utils1.class.getClassLoader().getResourceAsStream("druid.properties");
        try {
            properties.load(resourceAsStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            dataSource= DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //对外提供获取连接方法:
    public static Connection getConnection() throws SQLException {
        //先查看线程本地变量中是否存在
        Connection connection = tl.get();
        if(connection==null){
            //线程本地变量中没有,连接池获取
            connection=dataSource.getConnection();
            //存入线程本地变量
            tl.set(connection);
        }
        return connection;
    }
    //回收方法:
    public static void freeConnection() throws SQLException {
        Connection connection=tl.get();
        if(connection!=null){
            //清空线程本地变量
            tl.remove();
            connection.setAutoCommit(true);//要回归到初始状态,当开启事务的时候是false;
            connection.close();//回收到连接池;
        }
        connection.close();
    }
}

代码四:对转账练习的优化(使用连接池以及工具类)

package data_test8.daoANDservice;

import data_test8.jdbc_util2;

import java.sql.Connection;
import java.sql.PreparedStatement;

//TODO 此类是对bank表的一些操作;
public class BankDao {
    //account 加钱的账号,money:加钱的金额;这里需要设计jdbc因为是对数据库中的表中数据进行操作:
    public  void add(String account,int money)throws Exception{
        //TODO 可以直接从连接池中获取:
        Connection connection = jdbc_util2.getConnection();
        String sql="update t_bank set money=money+? where account=?;";
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        preparedStatement.setObject(1,money);
        preparedStatement.setObject(2,account);
        int i = preparedStatement.executeUpdate();
        preparedStatement.close();
        //connection.close();
        System.out.println("加钱成功!");
    }
    public  void sub(String account,int money)throws Exception{
//TODO 直接从连接池中获取
        Connection connection = jdbc_util2.getConnection();
        String sql="update t_bank set money=money-? where account=?;";
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        preparedStatement.setObject(1,money);
        preparedStatement.setObject(2,account);
        int i = preparedStatement.executeUpdate();
        preparedStatement.close();
        //connection.close();
        System.out.println("扣钱成功!");

    }
}
package data_test8.daoANDservice;

import data_test8.jdbc_util2;
import org.junit.Test;

import java.sql.Connection;
import java.sql.DriverManager;

//TODO 转账测试:
//TODO 银行卡业务方法,调用Dao中的方法;
public class BankService {
    @Test
    public void start() throws Exception {
        //hello给hi转账500块:
        transfer("hi","hello",500);
    }

    public void transfer(String addAccount,String subAccount,int money) throws Exception {
        BankDao bankDao=new BankDao();

//TODO 直接从连接池中获取
        Connection connection = jdbc_util2.getConnection();
        try{
            //设置不自动提交事务,开启事务:
            connection.setAutoCommit(false);
            bankDao.add(addAccount,money);
            bankDao.sub(subAccount,money);
            //事务提交:
            connection.commit();
        }catch(Exception e){
            //事务回滚:
            connection.rollback();
            //抛出异常:
            throw e;
        }finally {
            jdbc_util2.freeConnection();
        }
    }
}

代码五:对sql语句进行封装,结合工具类以及连接池对增删改查操作的优化;

package data_test9;//TODO 首先jdbc中一共有八步:1.注册驱动2.创建连接3.编写sql语句4创建statement5.占位符赋值6.发送sql语句7.结果解析8.回收资源;

import data_test8.jdbc_util2;

import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

// TODO 对于test8中的工具类只封装好了1.注册驱动2.创建连接8.回收资源,因此3.4.5.6.7.这五步没有完成;因此需要用高级应用层封装对这五步进行封装;
// TODO 基本每一个数据表都有一个对应的DAO接口以及其实现类,对其进行增删改查,但是这些操作重复性很高,所以可以抽取出公共的代码,然后给这些DAO的实现类可以抽取一个公共的父类,称为BaseDao;
//TODO 对于查询操作需要用executeQuery,增删改操作需要用executeUpdate,所以增删改一体,查询一体;
public class BaseDao {

    public int executeUpdate(String sql,Object...params) throws SQLException {
        //TODO 此处是对非查询语句方法的封装:sql是传入的带占位符的sql语句;params是占位符的值,此处用了可变参数(注意,可变参数可以直接当作数组使用);

        Connection connection = jdbc_util2.getConnection();
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        for(int i=0;i<params.length;i++){//TODO 注意此处
            preparedStatement.setObject(i+1,params[i]);
        }
        int rows = preparedStatement.executeUpdate();
        //是否回收连接,需要考虑是否是事务,如果将setAutoCommit设置为false代表事务开始,不自动提交,这一系列的操作,要么全部执行成功,要么全部都不成功;如果开启事务了,就不用管,业务层去处理;
        if(connection.getAutoCommit()){//可以通过这个方法来获取是否是false还是true也就是事务是否开启
            //如果为true代表没有开启事务,此时就需要回收;
            jdbc_util2.freeConnection();

        }
        return rows;
    }
    /*
    对于非查询语句的方法返回值是int类型,代表了影响的行数;但是对于查询语句方法返回的是什么类型呢,确实是一个集合,但并不是list<Map>,map没有数据校验机制,并且不支持反射操作;
    其实数据库数据-》对应java的实体类,有一个表:user表,里面有id,name,account,password属性,此时这个表对应一个java类:User类,有id,name,account,password属性,那么表中的一行数据,代表java类的一个对象,——》多行——》List<java实体类>list;
    java实体类可以校验并且支持反射操作;
    那么返回值的类型就是某一个实体类的集合
    <T>声明一个泛型,不确定类型;第一个<T>表示这个方法是一个泛型方法,可以用于指定查询结果的类型;List<T>表示该方法返回的是一个包含T类型的对象的集合,下方的Class<T>由外面传入,确定这个泛型的类型,例如传入一个User类,那么这个泛型就是User类型,还有一个好处就是可以使用这个类的反射机制给属性赋值
    public <T> List<T> executeQuery(Class<T>cla,String sql,Object...params)
    具体实现如下:
     */
    public <T> List<T> executeQuery(Class<T> cla, String sql, Object...params) throws Exception {
        //获取连接:
        Connection connection = jdbc_util2.getConnection();
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        //占位符赋值:
        if(params!=null&&params.length!=0){
            for(int i=0;i<params.length;i++){
                preparedStatement.setObject(i+1,params[i]);
            }
        }
        //执行sql语句:
        ResultSet resultSet = preparedStatement.executeQuery();
        //结果解析:
        List<T>list=new ArrayList<>();
        ResultSetMetaData metaData = resultSet.getMetaData();
        //获取列的数量,也就是属性的数量;
        int columnCount = metaData.getColumnCount();
        while(resultSet.next()){
            T t=cla.newInstance();//利用反射调用类的无参构造函数实例化对象!
            for(int i=1;i<=columnCount;i++){
                //得到本行i列属性的值
                Object object=resultSet.getObject(i);
                //得到本行i列的属性名:
                String columnLabel = metaData.getColumnLabel(i);
                //此时得到了这一列属性名和属性值,也就是给这个类的实例化对象的属性赋值,可以利用反射实现:
                Field field = cla.getDeclaredField(columnLabel);
                field.setAccessible(true);//属性可能是私用的,这样就可以打破private修饰限制,属性可以被设置;
                //给对象的属性赋值:第一个参数是想要赋值的对象,如果属性为静态的,可以为null;第二个参数是属性值:
                field.set(t,object);

            }
            list.add(t);
        }
        //关闭资源:
        resultSet.close();
        preparedStatement.close();
        if(connection.getAutoCommit()){
            //没有事务可以关闭:
            jdbc_util2.freeConnection();
        }
        return list;
    }


}
package data_test9;

import org.junit.Test;

import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
//TODO 利用新封装的BaseDao类,对增删改查进行优化:
public class better extends BaseDao {//TODO 此处需要继承一下BaseDao这样就有了其中的Update方法;
    public static void main(String[] args) {

    }
    @Test
    public void testInsert() throws Exception {
//        //对于job_grades表:添加A 1500 3000这条数据
//        //1.创建驱动:
//        Class.forName("com.mysql.jdbc.Driver");
//        //2.创建连接:
//        Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/atguigudb","root","dir99");
//        //3.编写sql语句以及创建prepareStatement
//        String sql="insert into job_grades values(?,?,?)";
//        PreparedStatement preparedStatement = connection.prepareStatement(sql);
//        preparedStatement.setObject(1,"A");
//        preparedStatement.setObject(2,1500);
//        preparedStatement.setObject(3,3000);
//        //发送sql语句:
//        int i = preparedStatement.executeUpdate();
//        if(i>0){
//            System.out.println("数据插入成功!");
//        }else{
//            System.out.println("数据插入失败!");
//        }
//        preparedStatement.close();
//        connection.close();
        String sql="insert into job_grades values(?,?,?)";
        int a = executeUpdate(sql, "A", 88888, 66666);//返回影响行数;


    }
    @Test
    public void testDelete()throws Exception{
//        Class.forName("com.mysql.jdbc.Driver");
//        Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/atguigudb", "root", "dir99");
//        String sql="delete from job_grades where grade_level=?";
//        PreparedStatement preparedStatement = connection.prepareStatement(sql);
//        preparedStatement.setObject(1,"F");
//        int i = preparedStatement.executeUpdate();
//        if(i>0){
//            System.out.println("删除成功!");
//        }else{
//            System.out.println("删除失败!");
//        }
//        preparedStatement.close();
//
        String sql="delete from job_grades where grade_level=? and lowest_sal=?";
        executeUpdate(sql,"A",88888);

    }
    @Test
    public void testUpdate()throws Exception{
        //对于job_grades表:将刚添加的A 1500 3000这条数据中3000改为9999;
//        Class.forName("com.mysql.jdbc.Driver");
//        Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/atguigudb", "root", "dir99");
//        String sql="update job_grades set highest_sal=? where lowest_sal=?";
//        PreparedStatement preparedStatement = connection.prepareStatement(sql);
//        preparedStatement.setObject(1,9999);
//        preparedStatement.setObject(2,1500);
//        int i = preparedStatement.executeUpdate();
//        if(i>0){
//            System.out.println("更新成功!");
//        }else{
//            System.out.println("更新失败!");
//        }
//        preparedStatement.close();
//        connection.close();
        String sql="update job_grades set highest_sal=? where lowest_sal=?";
        int i = executeUpdate(sql,99999,66666);


    }
    @Test
    //注意此处查询想查询所有数据,然后将数据放入到List<Map>list集合中:
    //可知查询结果是一行一行的,返回的是resultSet,然后将一行存入到map中,map(key=列名,value=列的内容)-》List<Map> list;
    //实现思路:遍历每一行数据,一行对应一个map,获取一行的列名和对应的列的属性,装配即可;然后将map装到一个集合当中就完成了;
    public void testSearch()throws Exception{
//        Class.forName("com.mysql.jdbc.Driver");
//        Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/atguigudb", "root", "dir99");
//        String sql="select * from job_grades";
//        PreparedStatement preparedStatement = connection.prepareStatement(sql);
//        ResultSet resultSet = preparedStatement.executeQuery();
//        //TODO 获取列的信息对象:避免手动获取每一个列的数据,metaData装的是当前结果集中列的信息对象(它可以根据下角标获取列的名称,也可以获取列的数量);
//        ResultSetMetaData metaData = resultSet.getMetaData();
//        //列的数量:有了它以后就可以水平遍历列:
//        int columnCount = metaData.getColumnCount();
//        List<Map> list=new ArrayList<>();
//        while(resultSet.next()){
//            //一行对应一个map;
//            Map map=new HashMap();
//            //下面这种方式纯手动提取,如果列的个数更多会非常麻烦并且换一个表就得重新写,效率很低;
            map.put("gradelevel",resultSet.getString(1));
            map.put("lowestsal",resultSet.getInt(2));
            map.put("highestsal",resultSet.getInt(3));
//            //新的方法读取每一个属性的数据,自动遍历列,注意要从一开始,和数据区分开
//            for(int i=1;i<=columnCount;i++){
//                //获取对应列的属性值:
//                Object value = resultSet.getObject(i);
//                //要是想加入map中,需要传入key和value,value已经有了,但是key:列名还没有:获取列的名称:这个方法可以获取列的别名,getcolumnname方法会获取列的名称,万一要是起了别名,就找不到了;
//                String columnLabel = metaData.getColumnLabel(i);
//                map.put(columnLabel,value);
//            }
//            list.add(map);
//        }
//        System.out.println(list);
//        for(Object data:list){
//            System.out.println(data);
//        }
//        resultSet.close();
//        preparedStatement.close();
//        connection.close();
        String sql="select * from job_grades";
        Class<Job_grades> clas = Job_grades.class;
        List<Job_grades> a = executeQuery(clas, sql);
        for (Object o:a){
            System.out.println(o);
        }
    }
}
class Job_grades{
    private String grade_level;
    private int lowest_sal;
    private int highest_sal;
    public String toString(){
        return grade_level+" "+lowest_sal+" "+highest_sal;
    }


}
package data_test9;

import org.junit.Test;

import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
//TODO 利用新封装的BaseDao类,对增删改查进行优化:
public class better extends BaseDao {//TODO 此处需要继承一下BaseDao这样就有了其中的Update方法;
    public static void main(String[] args) {

    }
    @Test
    public void testInsert() throws Exception {
//        //对于job_grades表:添加A 1500 3000这条数据
//        //1.创建驱动:
//        Class.forName("com.mysql.jdbc.Driver");
//        //2.创建连接:
//        Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/atguigudb","root","dir99");
//        //3.编写sql语句以及创建prepareStatement
//        String sql="insert into job_grades values(?,?,?)";
//        PreparedStatement preparedStatement = connection.prepareStatement(sql);
//        preparedStatement.setObject(1,"A");
//        preparedStatement.setObject(2,1500);
//        preparedStatement.setObject(3,3000);
//        //发送sql语句:
//        int i = preparedStatement.executeUpdate();
//        if(i>0){
//            System.out.println("数据插入成功!");
//        }else{
//            System.out.println("数据插入失败!");
//        }
//        preparedStatement.close();
//        connection.close();
        String sql="insert into job_grades values(?,?,?)";
        int a = executeUpdate(sql, "A", 88888, 66666);//返回影响行数;


    }
    @Test
    public void testDelete()throws Exception{
//        Class.forName("com.mysql.jdbc.Driver");
//        Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/atguigudb", "root", "dir99");
//        String sql="delete from job_grades where grade_level=?";
//        PreparedStatement preparedStatement = connection.prepareStatement(sql);
//        preparedStatement.setObject(1,"F");
//        int i = preparedStatement.executeUpdate();
//        if(i>0){
//            System.out.println("删除成功!");
//        }else{
//            System.out.println("删除失败!");
//        }
//        preparedStatement.close();
//
        String sql="delete from job_grades where grade_level=? and lowest_sal=?";
        executeUpdate(sql,"A",88888);

    }
    @Test
    public void testUpdate()throws Exception{
        //对于job_grades表:将刚添加的A 1500 3000这条数据中3000改为9999;
//        Class.forName("com.mysql.jdbc.Driver");
//        Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/atguigudb", "root", "dir99");
//        String sql="update job_grades set highest_sal=? where lowest_sal=?";
//        PreparedStatement preparedStatement = connection.prepareStatement(sql);
//        preparedStatement.setObject(1,9999);
//        preparedStatement.setObject(2,1500);
//        int i = preparedStatement.executeUpdate();
//        if(i>0){
//            System.out.println("更新成功!");
//        }else{
//            System.out.println("更新失败!");
//        }
//        preparedStatement.close();
//        connection.close();
        String sql="update job_grades set highest_sal=? where lowest_sal=?";
        int i = executeUpdate(sql,99999,66666);


    }
    @Test
    //注意此处查询想查询所有数据,然后将数据放入到List<Map>list集合中:
    //可知查询结果是一行一行的,返回的是resultSet,然后将一行存入到map中,map(key=列名,value=列的内容)-》List<Map> list;
    //实现思路:遍历每一行数据,一行对应一个map,获取一行的列名和对应的列的属性,装配即可;然后将map装到一个集合当中就完成了;
    public void testSearch()throws Exception{
//        Class.forName("com.mysql.jdbc.Driver");
//        Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/atguigudb", "root", "dir99");
//        String sql="select * from job_grades";
//        PreparedStatement preparedStatement = connection.prepareStatement(sql);
//        ResultSet resultSet = preparedStatement.executeQuery();
//        //TODO 获取列的信息对象:避免手动获取每一个列的数据,metaData装的是当前结果集中列的信息对象(它可以根据下角标获取列的名称,也可以获取列的数量);
//        ResultSetMetaData metaData = resultSet.getMetaData();
//        //列的数量:有了它以后就可以水平遍历列:
//        int columnCount = metaData.getColumnCount();
//        List<Map> list=new ArrayList<>();
//        while(resultSet.next()){
//            //一行对应一个map;
//            Map map=new HashMap();
//            //下面这种方式纯手动提取,如果列的个数更多会非常麻烦并且换一个表就得重新写,效率很低;
            map.put("gradelevel",resultSet.getString(1));
            map.put("lowestsal",resultSet.getInt(2));
            map.put("highestsal",resultSet.getInt(3));
//            //新的方法读取每一个属性的数据,自动遍历列,注意要从一开始,和数据区分开
//            for(int i=1;i<=columnCount;i++){
//                //获取对应列的属性值:
//                Object value = resultSet.getObject(i);
//                //要是想加入map中,需要传入key和value,value已经有了,但是key:列名还没有:获取列的名称:这个方法可以获取列的别名,getcolumnname方法会获取列的名称,万一要是起了别名,就找不到了;
//                String columnLabel = metaData.getColumnLabel(i);
//                map.put(columnLabel,value);
//            }
//            list.add(map);
//        }
//        System.out.println(list);
//        for(Object data:list){
//            System.out.println(data);
//        }
//        resultSet.close();
//        preparedStatement.close();
//        connection.close();
        String sql="select * from job_grades";
        Class<Job_grades> clas = Job_grades.class;
        List<Job_grades> a = executeQuery(clas, sql);
        for (Object o:a){
            System.out.println(o);
        }
    }
}
class Job_grades{
    private String grade_level;
    private int lowest_sal;
    private int highest_sal;
    public String toString(){
        return grade_level+" "+lowest_sal+" "+highest_sal;
    }


}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/293855.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

太阳能组件紫外预处理试验箱

太阳能组件紫外预处理试验箱波长范围&#xff1a;280-400nm用于太阳能光伏组件的温湿度及相类似紫外预处理环境的试验&#xff0c;主要用于太阳能组件材料评估诸如聚合物和保护层等材料抗紫外辐照能力&#xff0c;在预处理试验过程中能够快速、真实地再现阳光、雨、露等环境及对…

Etcd安装以及操作

Etcd介绍 etcd 是一个高度一致的分布式键值 (key-value) 存储&#xff0c;它提供了一种可靠的方式来存储需要由分布式系统或机器集群访问的数据。它可以优雅地处理网络分区期间的领导者选举&#xff0c;即使在 领导者节点中也可以容忍机器故障。 etcd 是用 Go 语言编写的&a…

Spring MVC响应结合RESTful风格开发,打造具有强大功能和良好体验的Web应用!

响应与Rest风格 1.11.1.1 环境准备步骤1:设置返回页面步骤2:启动程序测试 1.1.2 返回文本数据步骤1:设置返回文本内容步骤2:启动程序测试 1.1.3 响应JSON数据响应POJO对象响应POJO集合对象 知识点1&#xff1a;ResponseBody 2&#xff0c;Rest风格2.1 REST简介2.2 RESTful入门案…

Linux上搭建YApi

YApi是http接口管理和测试的重要工具&#xff0c;其作用相当于原来用的postman&#xff0c;但是比postman有更多的功能&#xff0c;本篇文章主要介绍如何在linux环境中快速的安装&#xff08;利用yum命令安装&#xff09;和部署YApi 一、nodejs 安装 1.1 下载nodejs包 yum i…

iPaaS与ETL:了解它们的主要区别

平均每个组织使用 130 多个应用程序&#xff0c;这一数字同比增长 30%。 随着公司试图充分利用其不断增长的应用程序生态系统&#xff0c;他们已经转向可以集成它们和/或其数据的工具。两个常用选项包括集成平台即服务 &#xff08;iPaaS&#xff09; 和提取、传输、加载 &…

pytorch08:学习率调整策略

目录 一、为什么要调整学习率&#xff1f;1.1 class _LRScheduler 二、pytorch的六种学习率调整策略2.1 StepLR2.2 MultiStepLR2.3 ExponentialLR2.4 CosineAnnealingLR2.5 ReduceLRonPlateau2.6 LambdaLR 三、学习率调整小结四、学习率初始化 一、为什么要调整学习率&#xff…

宝宝洗衣机哪个牌子质量好?好用的小型洗衣机推荐

当婴儿的到来&#xff0c;确实会给家庭带来许多变化&#xff0c;就好比如对于宝宝相关衣物的清洗需求。对于新生儿及婴幼儿的衣服&#xff0c;一般都要给予特殊的照顾与清洗&#xff0c;以保证不含细菌及过敏原。尤其是刚刚出生的婴儿&#xff0c;这时候宝宝们的皮肤很是幼嫩。…

JAVA基础学习笔记-day12-泛型

JAVA基础学习笔记-day12-泛型 1. 泛型概述1.1 泛型的引入 2. 使用泛型举例2.1 集合中使用泛型2.2 相关使用说明 3. 自定义泛型结构3.1 泛型的基础说明3.2 自定义泛型类或泛型接口3.2.1 说明3.2.2 注意 3.3 自定义泛型方法3.3.1 说明 4. 泛型在继承上的体现5. 通配符的使用5.1 通…

MySQL面试题汇总

常规&#xff1a; 1、数据库三大范式 1NF : 表中字段的数据不可再拆分。(原子性)2NF : 在满足第一范式的情况下&#xff0c;遵循唯一性&#xff0c;消除部分依赖。即&#xff0c;表中任意一个主键或任意一组联合主键&#xff0c;可以确定除该主键外的所有的非主键值。(一个表…

(适趣AI)Vue笔试题

&#x1f4d1;前言 本文主要是【Vue】——&#xff08;适趣AI&#xff09;Vue笔试题的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 …

Android studio报错误提示 Some Kotlin libraries attached to this project 问题解决方案

前些天发现了一个蛮有意思的人工智能学习网站,8个字形容一下"通俗易懂&#xff0c;风趣幽默"&#xff0c;感觉非常有意思,忍不住分享一下给大家。 &#x1f449;点击跳转到教程 Android新建项目后&#xff0c;报以下错误 错误提示内容为&#xff1a; 这个项目附带的一…

pygame学习(二)——绘制线条、圆、矩形等图案

导语 pygame是一个跨平台Python库(pygame news)&#xff0c;专门用来开发游戏。pygame主要为开发、设计2D电子游戏而生&#xff0c;提供图像模块&#xff08;image&#xff09;、声音模块&#xff08;mixer&#xff09;、输入/输出&#xff08;鼠标、键盘、显示屏&#xff09;模…

Spring Boot 与 Spring 框架的区别

一、前言 Spring Boot 和 Spring 框架是由 Spring 项目提供的两个关键的技术栈&#xff0c;它们在 Java 开发中扮演着不同的角色。在阐述其区别之前&#xff0c;我们先大致了解下这两个框架 二、Spring 框架 1、背景 Spring 框架是一个全栈的企业应用开发框架&#xff0c;起…

营销的尽头是矩阵!如何通过小魔推短视频矩阵快速破圈?

“ 营销的尽头是矩阵&#xff01; 相信很多做互联网的朋友都听过这么一句话 在抖音上我们看到过大批的博主&#xff0c;都是通过矩阵的方式火遍全网&#xff0c;就比如张琦、小杨哥等等&#xff0c;矩阵的方式适用于大多数的实体品牌&#xff0c;以及个人IP 等&#xff0c…

DevOps(3)

目录 11.描述root账户&#xff1f; 12.如何在发出命令时打开命令提示符&#xff1f; 14.Linux系统下交换分区的典型大小是多少&#xff1f; 15.什么是符号链接&#xff1f; 11.描述root账户&#xff1f; root账户就像一个系统管理员账户&#xff0c;允许你完全控制系统。 …

目标跟踪算法中的卡尔曼滤波学习

在使用多目标跟踪算法时&#xff0c;接触到卡尔曼滤波&#xff0c;一直没时间总结下&#xff0c;现在来填坑。 1. 背景知识 在理解卡尔曼滤波前&#xff0c;有几个概念值得考虑下&#xff1a;时序序列模型&#xff0c;滤波&#xff0c;线性动态系统 1. 时间序列模型 时间序…

AspectJ入门(二)— 应用

AspectJ便于调试、测试和性能调整工作。定义的行为范围从简单的跟踪到分析&#xff0c;再到应用程序内部一致性到测试。AspectJ可以干净地模块化这类功能&#xff0c;从而可以在需要时轻松地启用和禁用这些功能。 1 基础 本节将继续介绍AspectJ到一些基础功能&#xff0c;为后…

负载均衡案例:如何只用2GB内存统计20亿个整数中出现次数最多的整数

基于python实现。 如果是常规的小型文件&#xff0c;我们可以迅速地想到要建立字典。 以数字为key&#xff0c;以数字的出现次数为value&#xff0c;建立<int,int>类型的键值对存入字典&#xff0c;然后使用 max 函数结合字典的 items 方法来找到一个字典中 value 最大的…

2023 波卡年度报告选读:Polkadot SDK 与开发者社区

原文&#xff1a;https://dashboards.data.paritytech.io/reports/2023/index.html#section6 编译&#xff1a;OneBlock 编者注&#xff1a;Parity 数据团队发布的 2023 年 Polkadot 年度数据报告&#xff0c;对推动生态系统的关键数据进行了深入分析。报告全文较长&#xff…

一键减低PNG像素,轻松优化图片质量!

在数字时代&#xff0c;我们每天都要处理大量的图片文件&#xff0c;从网站设计、广告素材到社交媒体图片等。PNG作为一种常用的无损压缩格式&#xff0c;在保证图片质量的同时&#xff0c;也占用了较大的存储空间。为了优化存储空间和提高加载速度&#xff0c;我们需要对PNG图…
最新文章