jdbc基础

TOC

jdbc基础

JDBC概述

  JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问(不同数据库是有差异的,用jdbc都可以访问,相当于屏蔽了不同数据库之间的差异),它由一组用Java语言编写的类和接口组成。是Java访问数据库的标准规范
  JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。(JDBC使用者不能自己写实现类,只能使用接口)
  JDBC需要连接驱动(mysql-connector-java-5.1.39-bin.jar),驱动是两个设备要进行通信(的必要软件),满足一定通信数据格式,数据格式由设备提供商规定,设备提供商为设备提供驱动软件,通过软件可以与该设备进行通信。
驱动程序:是一套实现类,满足sun公司给的接口,满足一定通信数据格式;
开发的时候,只需要关注接口就行,使用的时候,会自动调用的
JDBC定义:是一套API,是sun定义类或是接口;

JDBC原理

Java提供访问数据库规范称为JDBC,而生产厂商提供规范的实现类称为驱动。
驱动是类库,实现了sun规定的接口,
驱动程序类库,实现接口,重写方法

JDBC是接口,驱动是接口的实现,没有驱动将无法完成数据库连接,从而不能操作数据库!每个数据库厂商都需要提供自己的驱动,用来连接自己公司的数据库,也就是说驱动一般都由数据库生成厂商提供。

JDBC开发步骤

  1. 注册驱动.
    告知JVM使用的是哪一个数据库的驱动
  2. 获得连接.
    使用JDBC中的类,完成对MySQL数据库的连接(效率低)
  3. 获得语句执行平台
    通过连接对象获取对SQL语句的执行者对象
  4. 执行sql语句
    使用执行者对象,向数据库执行SQL语句
    获取到数据库的执行后的结果
  5. 处理结果
  6. 释放资源.
    一堆close()
public class jdbcTest {
    public static void main(String[] args) throws Exception {
        Class.forName("com.mysql.jdbc.Driver"); //加载驱动程序
        String connString = "jdbc:mysql://localhost:3306/db_database17";//"jdbc:mysql://localhost:3306/数据库名?useUnicode=true&characterEncoding=utf8"
        Connection conn = DriverManager.getConnection(connString,"root","123456");// 数据库的连接,有时帐号,密码
        Statement stat = conn.createStatement();// 得到一个Statement(不带参数的简单语),将SQL语句发送到数据库
        stat.executeUpdate("create table if not exists people (id char(10), name char(20), age int, gender bit ) ;");//创建表people(字段id...)
        stat.executeUpdate("insert into people values ('001', 'Tom', 18, 1);");//插入内容
        stat.executeUpdate("insert into people values ('002', 'Marry', 20, 0);");
        stat.executeUpdate("insert into people values ('003', 'Peter', 25, 1);");
        stat.executeUpdate("update people set age=age+1 where id='003';");//更新、修改数据
        String sql = "select * from people;";//查询,在people中查询*
        ResultSet rs = stat.executeQuery(sql);//executeQuery执行查询,结果导入result,
        while (rs.next()) {           //循环遍历,得到每一个记录,字段
            String name = rs.getString("name");
            int age = rs.getInt("age");
            boolean gender = rs.getBoolean(4);
            System.out.printf("name = %s; age = %d,gender =%s\n", name, age, (gender ? "male" : "female"));
        }
        rs.close();//查询结束
        conn.close();
    }
}

bit称为位数据类型,长度为1位,有两种取值:0和1,在输入0以外的其他值时,系统均把它们当1看待。这种数据类型常作为逻辑变量使用,用来表示真、假或是、否等二值选择。程序读取数据库出来之后的表现形式是true或者false,但是保存在数据库中的结构类型是0或者1,1表示true,0表示false。
gender bit ,insert时是0或1,读取时是:(gender?"true":"false"),1—true,0—false

获得链接

  • 方法1:
Connection con = DriverManager.getConnection(“jdbc:mysql://localhost:3306/数据库名”,”root”,”root”);
//有中文的时候,URL是:"jdbc:mysql://localhost:3306/数据库名?useUnicode=true&characterEncoding=utf8"

获得语句执行平台

Statement:有sql注入危险

获取Statement对象,将SQL语句发送到数据库,返回值是 Statement接口的实现类对象,,在mysql驱动程序

Statement stat = con.createStatement();
PreparedStatement:防止sql注入:

登录案例:
假设有登录案例SQL语句如下:
SELECT * FROM 用户表 WHERE NAME = 用户输入的用户名 AND PASSWORD = 用户输的密码;
此时,当用户输入正确的账号与密码后,查询到了信息则让用户登录。但是当用户输入的账号为XXX 密码为:XXX' OR 'a'='a'时,则真正执行的代码变为:
SELECT * FROM 用户表 WHERE NAME = 'XXX' AND PASSWORD ='XXX' OR 'a'='a';
此时,上述查询语句时永远可以查询出结果的。那么用户就直接登录成功了,显然我们不希望看到这样的结果,这便是SQL注入问题。
为此,我们使用PreparedStatement来解决对应的问题。

//定义
PreparedStatement pst =  con.prepareStatement(sql);
  • 设置参数:
setObject();
setInt();
setString();
等...
String sql = "SELECT * FROM users WHERE uname =? AND uaddress =?";
//调用Connection接口的方法prepareStatement,获取PrepareStatement接口的实现类
//方法中参数,SQL语句中的参数全部采用问号占位符
PreparedStatement pst =  con.prepareStatement(sql);
//调用pst对象set方法,设置问号占位符上的参数
pst.setObject(1, user);
pst.setString(2, pass);
//调用方法,执行SQL,获取结果集
ResultSet rs = pst.executeQuery();
while(rs.next()){
    System.out.println(rs.getString("uname ")+"  "+rs.getString("uaddress "));
}
常用方法
方法 定义
int executeUpdate(String sql); 执行执行数据库中的SQL语,insert update delete语句
返回值int,操作成功数据表多少行的行数
ResultSet executeQuery(String sql); 执行select语句.
boolean execute(String sql); 执行select返回true 执行其他的语句返回false

结果处理:ResultSet

ResultSet实际上就是一张二维的表格,我们可以调用其boolean next()方法指向某行记录,当第一次调用next()方法时,便指向第一行记录的位置,这时就可以使用ResultSet提供的getXXX(int col)方法(与索引从0开始不同个,列从1开始)来获取指定列的数据:

  • 获取一行数据:rs.next();
  • 获取列数据:
方法 定义(参数是int:第i列,参数是String:根据字段名获取内容)
Object getObject(int index) / Object getObject(String name) 获得对象
String getString(int index) / Object getObject(String name) 获得字符串
int getInt(int index) / Object getObject(String name) 获得整形
double getDouble(int index) / Object getDouble(String name) 获得双精度浮点型
其他...

释放资源

与IO流一样,使用后的东西都需要关闭!关闭的顺序是先得到的后关闭,后得到的先关闭。

rs.close();
stmt.close();
con.close();

JDBC工具类

“获得数据库连接”操作,将在以后的增删改查所有功能中都存在,可以封装工具类JDBCUtils。提供获取连接对象的方法,从而达到代码的重复利用。
该工具类提供方法:public static Connection getConnection ()。

/*
 * JDBC工具类
 */
public class JDBCUtils {
    //构造方法私有,防止别人创建
    private JDBCUtils(){}
    privatestatic Connection con ;
    static{
        try{
            Class.forName("com.mysql.jdbc.Driver");
            String url = "jdbc:mysql://localhost:3306/mybase";
            String username="root";
            String password="123";
            con = DriverManager.getConnection(url, username, password);
        }catch(Exception ex){
            //若连接失败,直接抛出
            throw new RuntimeException(ex+"数据库连接失败");
        }
    }
    /*
    * 定义静态方法,返回数据库的连接对象
    */
    public static Connection getConnection(){//连接数据库
        return con;
    }
    public static void close(Connection con,Statement stat){//关闭数据库
        closeStatement(stat);
        closeConn(conn);
    }
    public static void close(Connection con,Statement stat , ResultSet rs){
        closeResultSet(rs);
        close(con,stat)
    }
     /**
      * 释放连接
      * @param conn 连接
      */
     public static void closeConn(Connection conn){
          if(conn!=null){//空的时候,不用关闭
               try {
                    conn.close();
               } catch (SQLException e) {
                    e.printStackTrace();
               }
               conn=null;//对象为空的时候,垃圾回收快
          }
     }
     /**
      * 释放语句执行者
      * @param st 语句执行者
      */
     public static void closeStatement(Statement st){
          if(st!=null){
               try {
                    st.close();
               } catch (SQLException e) {
                    e.printStackTrace();
               }
               st=null;
          }
     }
     /**
      * 释放结果集
      * @param rs 结果集
      */
     public static void closeResultSet(ResultSet rs){
          if(rs!=null){
               try {
                    rs.close();
               } catch (SQLException e) {
                    e.printStackTrace();
               }
               rs=null;
          }
     }

}
  • 测试使用
public class JDBCDemo {
    public static void main(String[] args) throws Exception{
        //创建集合对象
        List<Sort> list = new ArrayList<>();//包是util下的
        try{
            //使用JDBC工具类,直接获取数据库连接对象(必须在同一个工程中)
            Connection con = JDBCUtils.getConnection();//JDBCUtils是工具类
            //连接获取数据库SQL语句执行者对象
            PreparedStatement pst = con.prepareStatement("SELECT * FROM sort");
            //调用查询方法,获取结果集
            ResultSet rs = pst.executeQuery();

            while(rs.next()){
                //获取到每个列数据,封装到Sort对象中,封装的内容直接写列名
                Sort s = new Sort(rs.getInt("sid"),rs.getString("sname"),rs.getDouble("sprice"),rs.getString("sdesc"));
                //封装的Sort对象,存储到集合中
                list.add(s);
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            JDBCUtils.close(con, pst, rs);//关闭不用的
        }

        //遍历List集合,输出
        for(Sort s : list){
            System.out.println(s);
        }
    }
}

在配置文件properties中设置数据库

  • properties在资源路径下:
InputStream in = JDBCUtilsConfig.class.getClassLoader().getResourceAsStream("database.properties");
Properties pro = new Properties();
pro.load(in);
String driverClass=pro.getProperty("driverClass");
String url = pro.getProperty("url");
String username = pro.getProperty("username");
String password = pro.getProperty("password");
  • properties在src中:
    在src中新建file,起名jdbc.properties
driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/day07
user=root
password=1234
ResourceBundle bundle = ResourceBundle.getBundle("jdbc");
// 获取指定的内容
String DRIVERCLASS = bundle.getString("driverClass");
String URL = bundle.getString("url");
String USER = bundle.getString("user");
String PASSWORD = bundle.getString("password");
练习

判断map中所有的用户名在userinfo表中是否存在存在则输出"该用户已注册",如果不存在将该用户名及对应的密码存入到userinfo表中

public class TestJdbc {
    public static void main(String[] args) throws Exception {
        HashMap<String, String> hm=new HashMap<>();
        hm.put("liuyan", "123456");
        hm.put("wangbaoqiang", "123321");
        hm.put("fangbian", "123abc321");
        Set<String> set=hm.keySet();
        //功能1:
        for(String key:set){
            String value=hm.get(key);
            System.out.println(key+"--"+value);
        }
        //功能2
        Class.forName("com.mysql.jdbc.Driver");
        Connection con=DriverManager.getConnection("jdbc:mysql://localhost:3306/stdb","","");
        PreparedStatement pst =null;
        ResultSet rs =null;
        for(String key:set){
            String value=hm.get(key);
            pst = con.prepareStatement("SELECT upassword FROM userinfo where uname='"+key+"'");
            rs =pst.executeQuery() ;
            if(rs.next()){
                if(value.equals(rs.getString("upassword"))){
                    System.out.println(key+"在数据库中已存在");
                }else{
                    pst = con.prepareStatement("INSERT into userinfo (uname,upassword ) values (?,?)");
                    pst.setString(1, key);
                    pst.setString(2, value);
                    pst.executeUpdate();
                }
            }else{
                pst = con.prepareStatement("INSERT into userinfo (uname,upassword ) values (?,?)");
                pst.setString(1, key);
                pst.setString(2, value);
                pst.executeUpdate();
            }
        }
        JdbcDemo.close(con, pst, rs);
    }
}




posted @ 2019-09-26 18:00  紫月java  阅读(200)  评论(0编辑  收藏  举报