zoukankan      html  css  js  c++  java
  • JDBC二部曲之_入门

    JDBC

    1 什么是JDBC?

    JDBC(Java DataBase Connectivity),即Java数据库连接!也就是说,Java程序员可以使用JDBC API来操作数据库。

    最早JDBC是Java EE中的规范,但是现在已经添加到Java SE中了。也就是说,JDBC API在JDK中就已经存在了。与JDBC相关的包有:java.sql和javax.sql两个包!

    2 JDBC原理

      早期SUN公司的天才们想编写一套可以连接天下所有数据库的API,但是当他们刚刚开始时就发现这是不可完成的任务,因为各个厂商的数据库服务器差异太大了。后来SUN开始与数据库厂商们讨论,最终得出的结论是,由SUN提供一套访问数据库的规范,并提供连接数据库的协议标准,然后各个数据库厂商会遵循SUN的规范提供一套访问自己公司的数据库服务器的API出现。SUN提供的范围命名为JDBC,而各个厂商提供的,遵循了JDBC规范的,可以访问自己数据库的API被称之为驱动!

    现在大家已经知道了,想使用JDBC必须要有驱动才可以,驱动就是JDBC中接口的实现,并且是针对自己厂商的数据库服务器的实现。我们使用的是MySQL数据库服务器,那么就需要有MySQL驱动。

    3.JDBC编码步骤

    连接数据库需要MySQL的JDBC驱动,即:mysql-connector-java-5.1.13-bin.jar。

    对数据库的操作可以大致分为两种:更新操作、查询操作。更新操作就是增、删、改,它没有结果,而查询操作是有结果的。

    1. A.       注册驱动
    2. B.        获取与数据库的连接
    3. C.       得到代表SQL语句的对象
    4. D.       发送SQL语句:DML、DQL
    5. E.        获取结果集
    6. F.        从结果集中获取数据
    7. G.       关闭

    1、注册驱动

           Driver d = new Driver();

           DriverManager.registerDriver(d);

    其中Driver是com.mysql.jdbc.Driver类型,这种方法使用了硬编码,也就是说将来如果想更换数据库是不可以的,因为代码中使用了MySQL提供的类。

    其实JDBC为了让我们不出现硬编码,要求各个厂商提供的驱动都要可以把自己来注册到DriverManager中,答案在Driver()的源码中。

        static {

           try {

               java.sql.DriverManager.registerDriver(new Driver());

           } catch (SQLException E) {

               throw new RuntimeException("Can't register driver!");

           }

        }

    上面代码是com.mysql.jdbc.Driver类中的静态代码块,它会new一个自己类型的对象,然后再把自己注册到DriverManager中。我们都知道static块会在类被加载时就会执行,也就是说,在JVM加载Driver类时,已经把一个Driver类的对象注册到DriverManager中了,所以我们就不需要再去注册了。我们只需要保证Driver类被加载就OK了!修改上面加载驱动的代码如下:

    Class.forName("com.mysql.jdbc.Driver");

    上面代码是用来加载com.mysql.jdbc.Driver类的代码,这样就可以把Driver注册到DriverManager中了!

      在我们的代码中,不要出现驱动Jar包中的类!这方便我们将来切换数据库!!!

    2、获取与数据库的连接

    //方式一:

    Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day10", "root", "sorry");

    //方式二:

    Properties props = new Properties();

    props.put("user", "root");//key看数据库的规定

    props.put("password", "sorry");

    props.put("useUnicode", "true");

    props.put("characterEncoding", "utf8");

    Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day10", props);

    //方式三:

    Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day10?user=root&password=sorry");

    还可以使用DriverManager的registerDriver()方法,但这个方法通常我们是不会使用的,因为使用它会导致对特定驱动的依赖。

    注意,数据库的URL需要查看相关文档,不同数据库不同版本,URL都不一定一样.

    URL:   协议(jdbc):子协议(mysql):主机:端口/数据库

      我们知道在使用DriverManager的getConnection()方法时需要给出三个参数,其中一个是url,下面我们来聊一聊这个url是什么东西。JDBC使用的URL用于描述数据的来源,它的语法如下:

    可以把它分为三个部分,每个部分中间都是冒号:

    l  其中第一部分是jdbc,这是固定的;

    l  第二部分为子协议名称,一般都是特定厂商的数据库名称,例如MySQL就是jdbc:mysql:…,Oracle就是jdbc:oracle:…;

    l  第三部分由数据库厂商来确定,这一部分通常需要说明数据库服务器主机的IP、端口,以及数据库名称。

    MySQL的url:jdbc:mysql://localhost:3306/mydb1

    其实还可以给url添加参数,最为常见的参数就是:

    l  useUnicode=true

    l  characterEncoding=UTF8

    这两个参数是指定获取的Connection使用的编码!当然如果没有指定,那么会使用当前MySQL数据库的字符编码集。因为我们在安装MySQL时已经指定的UTF8,所以就算不指定这两个参数,获取到的连接也同样是UTF8的。

    其实在不指定主机和端口时,默认也是连接localhost主机的3306端口,所以可以把url写成如下的样子:

    jdbc:mysql:///mydb1

    当然,最后的mydb1是要连接的数据库,这部分是不能少的。

    建议把url写完整了:

    jdbc:mysql://localhost:3306/mydb1?useUnicode=true&characterEncoding=UTF8

    3、得到代表SQL语句的对象

    Statement stmt = conn.createStatement();

    4、发送SQL语句:DML、DQL

    ResultSet rs = stmt.executeQuery("selcet chinese,english,math from student");

    //Statement常用方法

    //ResultSet executeQuery(String sql):sql一般是DQL语句, 用来发送查询语句.

    //int executeUpdate(String sql):sql一般是没有返回结果集的语句,比如DML、DDL。返回值是影响到的行数, 用来发送增、删、改语句

    //boolean execute(String sql):sql可以任何的语句。返回值:如果执行的sql语句有结果集,返回true,没有结果集,返回false

    5、如果是DQL语句,有结果,得到返回的结果

    6、遍历结果集

    while(rs.next()){

        System.out.println("---------------------------");

        System.out.print(rs.getObject("chinese")+" ");

        System.out.print(rs.getObject("english")+" ");

        System.out.println(rs.getObject("math"));

    }

    7、释放占用的资源(官方文档,最好写成工具类.)

    前面我们在获取Connection时使用了硬编码,把driverClassName、url、username、password都直接写到了Java代码中,如果将来需要更换数据库,或者更换用户来登录数据库,这都不方便,所以我们应该把连接数据库的数据写到配置文件中,例如:

    //JDBC工具类

    public class JdbcUtil {

        private static String driverClass;

        private static String url;

        private static String user;

        private static String password;

        

        static{

            try {

                //从配置文件中读取信息

                InputStream in = JdbcUtil.class.getClassLoader().getResourceAsStream("dbcfg.properties");

                Properties pro = new Properties();

                pro.load(in);

                driverClass = pro.getProperty("driverClass");

                url = pro.getProperty("url");

                user = pro.getProperty("user");

                password = pro.getProperty("password");

                

                Class.forName(driverClass);

            } catch (Exception e) {

                throw new ExceptionInInitializerError(e);

            }

        }

        

        public static Connection getConnection() throws Exception {

            return DriverManager.getConnection(url,user,password);

        }

        

        public static void release(ResultSet rs,Statement stat,Connection conn){

            if(rs!=null){

                try {

                    rs.close();

                } catch (SQLException e) {

                    e.printStackTrace();

                }

                rs = null;

            }

            if(stat!=null){

                try {

                    stat.close();

                } catch (SQLException e) {

                    e.printStackTrace();

                }

                stat = null;

            }

            if(conn!=null){

                try {

                    conn.close();

                } catch (SQLException e) {

                    e.printStackTrace();

                }

                conn = null;

            }

        }

    }

     

    3.SQL攻击

    在需要用户输入的地方,用户输入的是SQL语句的片段,最终用户输入的SQL片段与我们DAO中写的SQL语句合成一个完整的SQL语句!例如用户在登录时输入的用户名和密码都是为SQL语句的片段!

    演示SQL攻击

    首先我们需要创建一张用户表,用来存储用户的信息。

    CREATE TABLE tab_user(

           uid  CHAR(32) PRIMARY KEY,

           username       VARCHAR(30) UNIQUE KEY NOT NULL,

           PASSWORD        VARCHAR(30)

    );

     

    INSERT INTO tab_user VALUES('U_1001', 'zs', 'zs');

    SELECT * FROM tab_user;

    现在用户表中只有一行记录,就是zs。

    下面我们写一个login()方法!

        public void login(String username,   String password) {

           Connection con = null;

           Statement stmt = null;

           ResultSet rs = null;

           try {

               con = JdbcUtils.getConnection();

               stmt = con.createStatement();

               String sql = "SELECT * FROM tab_user WHERE " +

                      "username='" + username +

                      "' and password='" +   password + "'";

               rs = stmt.executeQuery(sql);

               if(rs.next()) {

                  System.out.println("欢迎" + rs.getString("username"));

               } else {

                  System.out.println("用户名或密码错误!");

               }

           } catch (Exception e) {

               throw new RuntimeException(e);

           } finally {

               JdbcUtils.close(con, stmt,   rs);

           }     

        }

    下面是调用这个方法的代码:

    login("a' or 'a'='a", "a' or 'a'='a");

    这行当前会使我们登录成功!因为是输入的用户名和密码是SQL语句片段,最终与我们的login()方法中的SQL语句组合在一起!我们来看看组合在一起的SQL语句:

    SELECT * FROM tab_user WHERE username='a' or 'a'='a' and password='a' or 'a'='a'

    2 防止SQL攻击

    过滤用户输入的数据中是否包含非法字符;

    分步交验!先使用用户名来查询用户,如果查找到了,再比较密码;

    使用PreparedStatement

    PreparedStatement是Statement的子接口,你可以使用PreparedStatement来替换Statement。

    PreparedStatement的好处:

    防止SQL攻击;

    提高代码的可读性,以可维护性;

    提高效率。(支持预编译SQL –占位符’? ’)

    2 PreparedStatement的使用

    String sql = “select * from   tab_student where s_number=?”;

    PreparedStatement pstmt = con.prepareStatement(sql);

    pstmt.setString(1, “S_1001”);

    ResultSet rs = pstmt.executeQuery();

    rs.close();

    pstmt.clearParameters();//再次使用时需要把原来的设置清空。

    pstmt.setString(1, “S_1002”);

    rs = pstmt.executeQuery();

    在使用Connection创建PreparedStatement对象时需要给出一个SQL模板,所谓SQL模板就是有“?”的SQL语句,其中“?”就是参数。

    在得到PreparedStatement对象后,调用它的setXXX()方法为“?”赋值,这样就可以得到把模板变成一条完整的SQL语句,然后再调用PreparedStatement对象的executeQuery()方法获取ResultSet对象。

    注意PreparedStatement对象独有的executeQuery()方法是没有参数的,而Statement的executeQuery()是需要参数(SQL语句)的。因为在创建PreparedStatement对象时已经让它与一条SQL模板绑定在一起了,所以在调用它的executeQuery()和executeUpdate()方法时就不再需要参数了。

    PreparedStatement最大的好处就是在于重复使用同一模板,给予其不同的参数来重复的使用它。这才是真正提高效率的原因。

    所以,建议大家在今后的开发中,无论什么情况,都去需要PreparedStatement,而不是使用Statement

    4.DAO解耦

    把控制权转移到外面,想要创建对象,必须先传参数依赖注入

    public void setDao(User dao){

    this.dao = dao;

    {

    另一种方式通过构造函数转过来

    单开就是  单例设计模式

        //到底使用哪一个,是由自己指定的。是new出来的,没法解耦    

        //如果由外部传入使用的实现类,这个过程称之为控制反转,就可以解耦了.IoC DI:依赖注入:Spring的核心

        //工厂创建模式,就是把创建的细节隐藏起来.

        private UserDao dao = DaoFactory.getInstance().getUserDaoImpl();// = new UserDaoMySQLEnhanceImpl();

    //    public UserServiceImpl(UserDao dao){//依赖注入方法一,通过构造方式

    //        this.dao = dao;

    //    }

    //    public void setDao(UserDao dao){//依赖注入方式二,通过set方法

    //        this.dao = dao;

    //    }

    //创建DAO实例的工厂:饿汉子式单例

    public class DaoFactory {

        //先创建工厂类,需要私有化,为了能一家在就实例化,需要静态修饰

        private static DaoFactory instance = new DaoFactory();

        //无参构造函数私有化

        private DaoFactory(){}

        //定义静态方法,调用类

        public static DaoFactory getInstance(){

            return instance;

        }

        //私有Properties类,

        private static Properties props = new Properties();

        static{

            //静态代码块,初始化就加载,这样就参数就可以使用字符串,就可以写到配置文件中.

            InputStream in = DaoFactory.class.getClassLoader().getResourceAsStream("dao.properties");

            try {

                props.load(in);

            } catch (IOException e) {

                throw new RuntimeException(e);

            }

        }

        //创建一个UserDaoImpl实例类,需要的参数读取配置文件

        //这样就进行了解耦,所有需要的参数可以通过修改配置文件来完成

        public UserDao getUserDaoImpl(){

            try {

                String daoImplName = props.getProperty("userDao");

                return (UserDao)Class.forName(daoImplName).newInstance();

            } catch (Exception e) {

                throw new RuntimeException(e);

            }

        }

    }

    5 小知识点

    读取二进制文件

    我们一直在向数据库保存varhcar、int、date等类型的数据,现在我们要尝试把一张图片或一个mp3保存到数据库中去。

    首先我们需要创建一张表,表中要有一个mediumblob(16M)类型的字段。

    CREATE TABLE tab_bin(

           id   INT       PRIMARY   KEY AUTO_INCREMENT,

           filename VARCHAR(100),

           data       MEDIUMBLOB

    );

      向数据库插入二进制数据需要使用PreparedStatement为原setBinaryStream(int, InputSteam)方法来完成。

               con = JdbcUtils.getConnection();

               String sql = "insert into tab_bin(filename,data) values(?,   ?)";

               pstmt = con.prepareStatement(sql);

               pstmt.setString(1, "a.jpg");

               InputStream in = new FileInputStream("f:\a.jpg");//得到一个输入流对象

               pstmt.setBinaryStream(2, in);// 为第二个参数赋值为流对象

               pstmt.executeUpdate();

    读取二进制数据,需要在查询后使用ResultSet类的getBinaryStream()方法来获取输入流对象。也就是说,PreparedStatement有setXXX(),那么ResultSet就有getXXX()。

               con = JdbcUtils.getConnection();

               String sql = "select filename,data from tab_bin where   id=?";

               pstmt = con.prepareStatement(sql);

               pstmt.setInt(1, 1);

               rs = pstmt.executeQuery();

               rs.next();

              

               String filename = rs.getString("filename");

               OutputStream out = new   FileOutputStream("F:\" + filename);

               //使用文件名来创建输出流对象。

               InputStream in =   rs.getBinaryStream("data");//读取输入流对象

               IOUtils.copy(in, out);// 把in中的数据写入到out中。

               out.close();

      还有一种方法,就是把要存储的数据包装成Blob类型,然后调用PreparedStatement的setBlob()方法来设置数据

           con = JdbcUtils.getConnection();

           String sql = "insert into tab_bin(filename,data) values(?, ?)";

           pstmt = con.prepareStatement(sql);

           pstmt.setString(1, "a.jpg");

           File file = new File("f:\a.jpg");

           byte[] datas = FileUtils.getBytes(file);//获取文件中的数据

           Blob blob = new SerialBlob(datas);//创建Blob对象

           pstmt.setBlob(2, blob);//设置Blob类型的参数

           pstmt.executeUpdate();

           con = JdbcUtils.getConnection();

           String sql = "select filename,data from tab_bin where id=?";

           pstmt = con.prepareStatement(sql);

           pstmt.setInt(1, 1);

           rs = pstmt.executeQuery();

           rs.next();

          

           String filename = rs.getString("filename");

           File file = new File("F:\" + filename) ;

           Blob blob = rs.getBlob("data");

           byte[] datas = blob.getBytes(0, (int)file.length());

           FileUtils.writeByteArrayToFile(file,   datas);

    批处理SQL

    语句不同,有很多行,可以使用addBatch方法批处理,别忘了executeBatch一下.

    其实Batch里面就是封装了一个缓存

        //向t1表中插入两条记录,删除第一条记录

        //利用statement可以执行SQL语句不同的批处理

        public void testBatch1(){

            Connection conn = null;

            Statement stmt = null;

            try{

                conn = JdbcUtil.getConnection();

                stmt = conn.createStatement();

                //把要输入的SQL语句放入字符串变量中去;

                String sql1 = "insert into t1 (id,name) values(1,'aaa1')";

                String sql2 = "insert into t1 (id,name) values(2,'bbb1')";

                String sql3 = "delete from t1 where id=1";

                //注入SQL语句,是注入,并没有执行;

                stmt.addBatch(sql1);

                stmt.addBatch(sql2);

                stmt.addBatch(sql3);

                

                //对注入的SQL语句执行

                //数组的元素表示每条语句影响到的行数。

                int[] i = stmt.executeBatch();

            }catch(Exception e){

                throw new RuntimeException(e);

            }finally{

                JdbcUtil.release(null, stmt, conn);

            }

            

        }

     

    利用PreparedStatement执行批处理,只能用在SQL语句相同的情况下。参数有可能不同

        //向t1表中批量插入10条记录,语句相同,参数不同

        @Test

        public void testBatch2(){

            Connection conn = null;

            PreparedStatement stmt = null;

            try{

                conn = JdbcUtil.getConnection();

                //一开始就需要把SQL语句加载到PreparedStatement中,用占位符

                String sql="insert into t1 (id,name) values(?,?)";

                stmt = conn.prepareStatement(sql);

                //输入SQL语句中的参数

                for(int x=0;x<10;x++){

                    stmt.setInt(1, x+1);

                    stmt.setString(2, "aaa"+(x+1));

                    //对参数进行注入

                    stmt.addBatch();

                }

                //对注入的参数执行

                stmt.executeBatch();

            }catch(Exception e){

                throw new RuntimeException(e);

            }finally{

                JdbcUtil.release(null, stmt, conn);

            }

        }

     

    OCI  效率高  但是要装客户文件

    Thin 效率低 但是不需要装

    一般开发用这个Thin

    插入1000001条记录,大数据插入

        //向t1表中批量插入1000001条记录

        @Test

        public void testBatch3(){

            Connection conn = null;

            PreparedStatement stmt = null;

            try{

                conn = JdbcUtil.getConnection();

                //一开始就需要把SQL语句加载到PreparedStatement中,用占位符

                String sql="insert into t1 (id,name) values(?,?)";

                stmt = conn.prepareStatement(sql);

                //输入SQL语句中的参数

                for(int x=0;x<1000001;x++){

                    stmt.setInt(1, x+1);

                    stmt.setString(2, "aaa"+(x+1));

                    stmt.addBatch();

                    //定义一个判断,每插入1000条就执行一次,还需要清空注入的语句.

                    if(x%1000==0){

                        stmt.executeBatch();//执行

                        stmt.clearBatch();//清空

                    }

                }

                //扫尾执行,因为可能会有尾数

                stmt.executeBatch();

            }catch(Exception e){

                throw new RuntimeException(e);

            }finally{

                JdbcUtil.release(null, stmt, conn);

            }

        }

    返回自增长主键

    当表的主键是自增长的,那么就是由数据库来维护主键的值。当我们使用Java向数据库插入一行记录后,主键的值我们是不知道的。当然你可以去再查询一次!但是这不是最好的办法。

    想获取主键自增长的值,需要在创建PreparedStatement时开始:

    String sql = "insert into tt2(name) values(?)";

    pstmt = con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);

    //表示在执行SQL语句后会去获取主键自增长的值。

    pstmt.setString(1,   "hello");

    pstmt.executeUpdate();

    在执行完INSERT语句之后,可以通过PrepareStatement的getGeneratedKeys()方法获取一个结果集对象,然后再获取结果集中唯一一行,唯一一列的数据,这就是主键自增长的值。

    ResultSet rs =   pstmt.getGeneratedKeys();//获取自增长主键结果集

    rs.next();

    int id = rs.getInt(1);

    System.out.println(id);

    调用存储过程

    1 创建存储过程

    首先创建3个存在过程:

    l  无参的;

    l  入参的;

    l  出参的。

    DELIMITER //

    CREATE PROCEDURE pro1()

    BEGIN

           SELECT   * FROM stu;

    END//

    DELIMITER ;

    DELIMITER //

    CREATE PROCEDURE pro2(IN _sid   VARCHAR(10))

    BEGIN

        SELECT * FROM stu WHERE sid=_sid;

    END//

    DELIMITER ;

    DELIMITER //

    CREATE PROCEDURE pro3(IN _sid   VARCHAR(10), OUT _sname VARCHAR(20))

    BEGIN

        SELECT sname INTO _sname FROM stu WHERE sid=_sid;

    END//

    DELIMITER ;

    2 调用pro1(无参存储过程)

    要调用存储过程需要使用CallableStatement,获取CallableStatement需要调用Connection的prepareCall(String sql)方法。

               con = JdbcUtils.getConnection();

               String sql = "{call pro1()}";//调用存储过程的SQL语句需要一对大括号括起来

               cstmt = con.prepareCall(sql);

               rs = cstmt.executeQuery();//如果存储过程会返回结果集,那么就调用executeQuery()方法,否则调用executeUpdate()方法。

               while(rs.next()) {

                  int colCnt =   rs.getMetaData().getColumnCount();

                  for(int i = 1; i <= colCnt; i++) {

                      Object o = rs.getObject(i);

                      System.out.print(o + " ");

                  }

                  System.out.println();

               }

    3 调用有入参存储过程

               con = JdbcUtils.getConnection();

               String sql = "{call pro2(?)}";//给出一个参数

               cstmt = con.prepareCall(sql);

               cstmt.setString(1, "S_100");//为参数赋值

               rs = cstmt.executeQuery();

               rs.next();

               System.out.println(rs.getString(1) + ", " + rs.getString(2)  

                      +   ", " + rs.getInt(3) + ", " + rs.getString(4));

    4 调用有出参的存储过程

               con = JdbcUtils.getConnection();

               String sql = "{call   pro3(?,?)}";//第一个参数是入参,第二个是出参。

     

               cstmt = con.prepareCall(sql);

               cstmt.setString(1, "S_100");

               cstmt.registerOutParameter(2, Types.VARCHAR);// 注册一个出参!说明它的SQL类型

     

               cstmt.execute();//这里调用executeUpdate()、executeQuery()或是execute()都行!

               String name = cstmt.getString(2);// 获取出参的值

               System.out.println(name);

    元数据

    1 DatabaseMetaData

    获取DatabaseMetaData对象:

    Connection con =   ...

    DatabaseMetaData   dbmd = con.getMetaData();

    基本功能

    String name =   dbmd.getDatabaseProductName();//获取数据库名称:MySQL

    int v1 = dbmd.getDatabaseMajorVersion();//获取数据库主版本号:5

    int v2 = dbmd.getDatabaseMinorVersion();//获取数据库次版本号:1

    System.out.println(name + v1 + "." + v2);

    String driverName   = dbmd.getDriverName();//获取驱动名

    String   driverVersion = dbmd.getDriverVersion();//获取驱动版本

    System.out.println(driverName   + ", " + driverVersion);

    String url =   dbmd.getURL();//获取URL

    String username =   dbmd.getUserName();//获取用户名

    System.out.println(url);

    System.out.println(username);

    获取所有数据库名称

    ResultSet rs =   dbmd.getCatalogs();

    while(rs.next()) {

        System.out.println(rs.getString(1));

    }

    获取指定数据库中所有表名称

    ResultSet rs =   dbmd.getTables("mydb1", null, null, new String[]{"TABLE"});

    while(rs.next())      {             

        System.out.println(rs.getString("TABLE_NAME"));

    }

    2 ParameterMetaData

    得到ParameterMataData对象

    Connection con = ...

    String sql = "insert into tab_student value(?,?,?,?)";

    PreparedStatement   pstmt = con.prepareStatement(sql);

    ParameterMetaData pmd =   pstmt.getParameterMetaData();

    ParameterMetaData是针对“?”的元数据!但是很多驱动对它的支持不是很好。

    int cnt = pmd.getParameterCount();//参数的个数

    for(int i = 1; i <= cnt; i++) {

        System.out.println(pmd.getParameterTypeName(i));//当前参数类型名

        System.out.println(pmd.getParameterType(i));//当前参数类型

        System.out.println(pmd.getParameterClassName(i));//当前参数Java类型名

        System.out.println(pmd.isNullable(i));//当前参数是否可以为NULL

    }

    3 结果集列数据:ResultSetMetaDate

    获取ResultSetMetaData

    ResultSet rs = ...;

    ResultSetMetaData rsmd = rs.getMetaData();

    方法介绍:

           ResultSetMetaData rsmd =   rs.getMetaData();

           int cnt = rsmd.getColumnCount();//获取结果集列数

          

           for(int i = 1; i <= cnt; i++) {

               System.out.print(rsmd.getColumnName(i));//获取当前列名称

               if(i < cnt) {

                  System.out.print(", ");

               }

           }

           System.out.println();

           for(int i = 1; i <= cnt; i++) {

               System.out.print(rsmd.getColumnClassName(i));//获取当前列Java类型名

               if(i < cnt) {

                  System.out.print(", ");

               }

           }

           System.out.println();

           while(rs.next()) {

               for(int i = 1; i <= cnt; i++) {

                  System.out.print(rs.getObject(i));//看清楚,这个是rs不是rsmd

                  if(i < cnt) {

                      System.out.print(", ");

                  }

               }

               System.out.println();

           }

  • 相关阅读:
    Redis进阶实践之一VMWare Pro虚拟机安装和Linux系统的安装
    HTTP常见面试题
    HBase WAL原理学习
    HBase TableExistsException: hbase:namespace
    HBase常用操作之namespace
    Hbase原理、基本概念、基本架构
    hbase 修复 hbase hbck
    hbase数据备份或者容灾方案
    Hbase 日常运维
    HBase shell scan 模糊查询
  • 原文地址:https://www.cnblogs.com/lulu638/p/4438853.html
Copyright © 2011-2022 走看看