后端开发——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 {@Testpublic 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.读取配置文件 PropertiesProperties 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 {@Testpublic 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) {}@Testpublic 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);//返回影响行数;}@Testpublic 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);}@Testpublic 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) {}@Testpublic 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);//返回影响行数;}@Testpublic 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);}@Testpublic 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.mzph.cn/news/597743.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

x-cmd pkg | tig - git 文本模式界面

目录 简介首次用户功能特点类似工具与竞品进一步探索 简介 tig 由 Jonas Fonseca 于 2006 年使用 C 语言创建的 git 交互式文本命令行工具。旨在开启交互模式快速浏览 git 存储库的信息以及 git 命令的运行。 首次用户 使用 x tig 即可自动下载并使用 在终端运行 eval "…

微服务之间互相调用出现的错误

场景&#xff1a; 微服务A调用微服务B的接口&#xff0c;微服务B的接口请求方式是get类型&#xff0c;传递的参数是JSON格式。 错误&#xff1a; 1、postman&#xff1a;springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserial…

Gin 框架介绍与快速入门

Gin 框架介绍与快速入门 文章目录 Gin 框架介绍与快速入门一、Gin框架介绍1. 快速和轻量级2. 路由和中间件3. JSON解析4. 支持插件5. Gin相关文档 二、基本使用1.安装2.导入3.第一个Gin 应用 三、应用举例四、Gin 入门核心1.gin.Engine2.gin.Context 一、Gin框架介绍 Gin是一个…

VitePress搭建Vite官方中文文档首页

✨专栏介绍 在当今数字化时代&#xff0c;Web应用程序已经成为了人们生活和工作中不可或缺的一部分。而要构建出令人印象深刻且功能强大的Web应用程序&#xff0c;就需要掌握一系列前端技术。前端技术涵盖了HTML、CSS和JavaScript等核心技术&#xff0c;以及各种框架、库和工具…

FinGPT——金融领域开源大模型

文章目录 背景论文摘要相关工作大型语言模型&#xff08;LLMs&#xff09;和ChatGPT金融领域的LLMs为什么需要开源的金融LLMs&#xff1f; 以数据为中心的方法用于FinLLMs金融数据和独特特性应对处理金融数据的挑战 FINGPT 概述&#xff1a;FINLLM 的开源框架数据来源面向金融N…

【常用排序算法】冒泡排序

冒泡排序 冒泡排序基本思想&#xff1a;N 个数的数组&#xff0c;经过N-1轮排序。 升序 大的值下沉&#xff0c;小的值上浮。降序 小的值下沉&#xff0c;小的字上浮 import java.util.Arrays; public class BubbleSort {public static void main(String[] args) {int[] values…

Git 对项目更新的时候提示错误 repository not owned by current user

遇到 Git 提示的错误信息为&#xff1a;repository not owned by current user 上图显示的是错误的信息。 问题和解决 出现上面错误信息的原因是当前文件夹的权限和 Git 的执行权限不一直导致的。 我们的问题是我们希望在网盘上使用 Git 更新克隆后的代码&#xff0c;但登录…

React Hook 原理,及如何使用Hook

一、 Hook使用规则 只在最顶层使用Hook 不要在循环&#xff0c;条件或嵌套函数中调用Hook&#xff1b; 只在组件函数和自定义hook中调用Hook Q1 &#xff1a; 为什么 hook 不能 在循环&#xff0c;条件或嵌套函数中调用Hook &#xff1f; A1&#xff1a; 因为这跟React的…

使用Kafka与Spark Streaming进行流数据集成

在当今的大数据时代&#xff0c;实时数据处理和分析已经变得至关重要。为了实现实时数据集成和分析&#xff0c;组合使用Apache Kafka和Apache Spark Streaming是一种常见的做法。本文将深入探讨如何使用Kafka与Spark Streaming进行流数据集成&#xff0c;以及如何构建强大的实…

【智慧地球】星图地球 | 星图地球超算数据工场

当前空天信息处理涉及并发并行的大量计算问题&#xff0c;需要高性能计算、智能计算联合调度&#xff0c;以此来实现多算力融合&#xff1b;而我国算力产业规模快速增长&#xff0c;超算算力资源正需要以任务驱动来统筹。 基于此&#xff0c;中科星图与郑州中心展开紧密合作&a…

从0开始python学习-39.requsts库

目录 HTTP协议 1. 请求 2. 响应 Requests库 1. 安装 2. 请求方式 2.1 requests.请求方式(参数) 2.2 requests.request() 2.3 requests.session().request() 2.4 三种方式之间的关联 3. 请求参数 3.1 params&#xff1a;查询字符串参数 3.2 data&#xff1a;Form表单…

【Python可视化实战】钻石数据可视化

一、项目引言 1.背景和目标 钻石作为一种珍贵的宝石&#xff0c;其价格受到多种因素的影响。为了深入了解钻石价格的决定因素&#xff0c;我们收集了大量关于钻石的数据&#xff0c;并希望通过数据可视化来揭示钻石特征与价格之间的关系。 2.内容 收集钻石的各项特征数据&a…

【大数据】分布式协调系统 Zookeeper

分布式协调系统 Zookeeper 1.Zookeeper 的特点2.Zookeeper 的数据结构3.Zookeeper 的应用场景3.1 统一命名服务3.2 统一配置管理3.3 统一集群管理3.4 服务器动态上下线3.5 软负载均衡 Zookeeper 是 Apache 开源的一个顶级项目&#xff0c;目的是为分布式应用提供协调服务&#…

IO进程线程 day4

进程状态间的转化 创建出三个进程完成两个文件之间拷贝工作&#xff0c;子进程1拷贝前一半内容&#xff0c;子进程2拷贝后一半内容&#xff0c;父进程回收子进程的资源 #include <head.h> int main(int argc, const char *argv[]) {FILE *fp1NULL,*fp2NULL;//定义两个文…

【Java基础篇】常见的字符编码、以及它们的区别

常见的字符编码、以及它们的区别 ✔️ 解析✔️扩展知识仓✔️Unicode和UTF-8有啥关系?✔️有了UTF-8&#xff0c;为什么要出现GBK✔️为什么会出现乱码 ✔️ 解析 就像电报只能发出 ”滴” 和 ”答” 声一样&#xff0c;计算机只认识 0 和 1 两种字符&#xff0c;但是&#x…

【驱动序列】C#获取电脑硬件基本组合以及基础信息

大家好&#xff0c;我是全栈小5&#xff0c;欢迎阅读《小5讲堂之知识点实践序列》文章。 这是2024年第7篇文章&#xff0c;此篇文章是C#知识点实践序列文章&#xff0c;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 要开发一款驱动小助手&…

vue封装基础input组件(添加防抖功能)

先看一下效果&#xff1a; // 调用页面 <template><div><!-- v-model&#xff1a;伪双向绑定 --><my-input v-model"inputVal" label"姓名" type"textarea" /></div> </template><script> import…

第3章 【例题】(完整版)

目录 前言 【例3.1】有关成绩结构体的例子 【例3.2】使用Score类的完整程序 【例 3.3】一个存在错误的程序 【例3.4】用对象赋值语句的例子 【例3.5】为类Score定义一个构造函数 【例3.6】建立对象的同时&#xff0c;用构造函数给数据成员赋初值 【例3.7】用成员初始…

【Spark精讲】Spark on Hive性能优化

目录 第一章 1.1 集群配置概述 1.2 集群规划概述 第二章 Yarn配置 2.1 Yarn配置说明 yarn.nodemanager.resource.memory-mb yarn.nodemanager.resource.cpu-vcores yarn.scheduler.maximum-allocation-mb yarn.scheduler.minimum-allocation-mb 第三章 Spark的配置说…

Vue3中配置env环境变量

什么时候会用到这个呢&#xff0c;比如我们的后端开发有多名&#xff0c;很多时候需要切换调用不同人的接口地址&#xff0c;或者在打包的时候&#xff0c;需要指定环境中的后台接口地址&#xff0c;那么我们频繁修改代码&#xff0c;就很麻烦&#xff0c;这个时候&#xff0c;…