Java中级/JDBC/1

Hello JDBC

为项目导入mysql-jdbc的jar包

访问MySQL数据库需要用到第三方的类,这些第三方的类,都被压缩在一个叫做Jar的文件里。
为了代码能够使用第三方的类,需要为项目导入mysql的专用Jar包。
该包mysql-connector-java-5.0.8-bin.jar可以在右边下载
通常都会把项目用到的jar包统一放在项目的lib目录下,在本例就会放在 E:\project\j2se\lib 这个位置
然后在eclipse中导入这个jar包

导包步骤:

 右键project->property->java build path->libaries->add external jars

初始化

通过Class.forName("com.mysql.jdbc.Driver");
初始化驱动类com.mysql.jdbc.Driver
就在 mysql-connector-java-5.0.8-bin.jar
如果忘记了第一个步骤的导包,就会抛出ClassNotFoundException
Class.forName是把这个类加载到JVM中,加载的时候,就会执行其中的静态初始化块,完成驱动的初始化的相关工作。

package jdbc;
   
public class TestJDBC {
    public static void main(String[] args) {
           
        //初始化驱动
        try {
            //驱动类com.mysql.jdbc.Driver
            //就在 mysql-connector-java-5.0.8-bin.jar中
            //如果忘记了第一个步骤的导包,就会抛出ClassNotFoundException
            Class.forName("com.mysql.jdbc.Driver");
              
            System.out.println("数据库驱动加载成功 !");
   
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
           
    }
}

建立与数据库的连接

建立与数据库的Connection连接
这里需要提供:
数据库所处于的ip:127.0.0.1 (本机)
数据库的端口号: 3306 (mysql专用端口号)
数据库名称 how2java
编码方式 UTF-8
账号 root
密码 admin
注: 这一步要成功执行,必须建立在mysql中有数据库how2java的基础上

package jdbc;
  
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
  
public class TestJDBC {
    public static void main(String[] args) {
  
        try {
            Class.forName("com.mysql.jdbc.Driver");
  
            // 建立与数据库的Connection连接
            // 这里需要提供:
            // 数据库所处于的ip:127.0.0.1 (本机)
            // 数据库的端口号: 3306 (mysql专用端口号)
            // 数据库名称 how2java
            // 编码方式 UTF-8
            // 账号 root
            // 密码 admin
  
            Connection c = DriverManager
                    .getConnection(
                            "jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8",
                            "root", "admin");
  
            System.out.println("连接成功,获取连接对象: " + c);
  
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
  
    }
}

创建Statement

Statement是用于执行SQL语句的,比如增加,删除

			Connection c = DriverManager
					.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8","root","admin");
			System.out.println("连接成功,获取连接对象: " + c);
			
			Statement s = c.createStatement();
			  
	        System.out.println("获取 Statement对象: " + s);

执行SQL语句

s.execute执行sql语句
执行成功后,用mysql-front进行查看,明确插入成功
执行SQL语句之前要确保数据库how2java中有表hero的存在,如果没有,需要事先创建表

			Connection c = DriverManager
					.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8","root","admin");
			System.out.println("连接成功,获取连接对象: " + c);
			
			Statement s = c.createStatement();
			  
	        String sql = "insert into hero values(4,"+"'龙王'"+","+313.0f+","+50+")";
            s.execute(sql);
  
            System.out.println("执行插入语句成功");

关闭连接

数据库的连接是有限资源,相关操作结束后,养成关闭数据库的好习惯
先关闭Statement
后关闭Connection

package jdbc;
 
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
 
public class TestJDBC {
    public static void main(String[] args) {
 
        Connection c = null;
        Statement s = null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
 
            c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8", "root",
                    "admin");
 
            s = c.createStatement();
 
            String sql = "insert into hero values(null," + "'提莫'" + "," + 313.0f + "," + 50 + ")";
 
            s.execute(sql);
 
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            // 数据库的连接时有限资源,相关操作结束后,养成关闭数据库的好习惯
            // 先关闭Statement
            if (s != null)
                try {
                    s.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            // 后关闭Connection
            if (c != null)
                try {
                    c.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
        }
    }
}

使用try-with-resource的方式自动关闭连接

如果觉得上一步的关闭连接的方式很麻烦,可以参考关闭流 的方式,使用try-with-resource的方式自动关闭连接,因为ConnectionStatement都实现了AutoCloseable接口

package jdbc;
  
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
  
public class TestJDBC {
    public static void main(String[] args) {
  
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
  
        try (
            Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8",
                "root", "admin");
            Statement s = c.createStatement();             
        )
        {
            String sql = "insert into hero values(null," + "'提莫'" + "," + 313.0f + "," + 50 + ")";
            s.execute(sql);
              
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

批量插入和删除:

            for (int i = 100; i <133; i++) {
                String name="'"+"英雄 "+i+"'";
                //插入
                //String sql="insert into hero values(null,"+name+","+100.0f+","+40+")";
                //删除 
                String sql = "delete from hero where id = ("+i+")";
                s.execute(sql);
            }

增删改

CRUD是最常见的数据库操作,即增删改查
C 增加(Create)
R 读取查询(Retrieve)
U 更新(Update)
D 删除(Delete)

增加

这段代码就是Hello JDBC中的代码,用于向数据库中插入数据:

 String sql = "insert into hero values(null," + "'提莫'" + "," + 313.0f + "," + 50 + ")";

删除

String sql = "delete from hero where id = 5";
s.execute(sql);

修改

String sql = "update hero set name = 'name 5' where id = 3";
s.execute(sql);

查询

查询语句

executeQuery 执行SQL查询语句
注意: 在取第二列的数据的时候,用的是rs.get(2) ,而不是get(1). 这个是整个Java自带的api里唯二的地方,使用基1的,即2就代表第二个。
另一个地方是在PreparedStatement这里

  • ps.setInt(1, i) 代表给 SQL 语句的第 1 个占位符 设置参数值,是针对 SQL 语句
  • rs.getInt(1) 代表获取某条记录的第 1 个字段值,是针对数据库的结果集.也是基1的,第一个是id。
  • 以上两个针对不同,需要注意!!!

api文档中ResultSet 光标最初位于第一行之前,所以当查找时。next()之后才移向了第一行

String sql = "select * from hero";
 
// 执行查询语句,并把结果集返回给ResultSet
ResultSet rs = s.executeQuery(sql);
   while (rs.next()) {
         int id = rs.getInt("id");// 可以使用字段名
         String name = rs.getString(2);// 也可以使用字段的顺序
          float hp = rs.getFloat("hp");
          int damage = rs.getInt(4);
          System.out.printf("%d\t%s\t%f\t%d%n", id, name, hp, damage);
            }
           // 不一定要在这里关闭ReultSet,因为Statement关闭的时候,会自动关闭ResultSet
           // rs.close();

SQL语句判断账号密码是否正确

  1. 创建一个用户表,有字段name,password
  2. 插入一条数据
insert into user values(null,'dashen','thisispassword');
  1. SQL语句判断账号密码是否正确

判断账号密码的正确方式是根据账号和密码到表中去找数据,如果有数据,就表明密码正确了,如果没数据,就表明密码错误。
不恰当的方式 是把uers表的数据全部查到内存中,挨个进行比较。 如果users表里有100万条数据呢? 内存都不够用的。
SQL代码:

CREATE TABLE User(
       id int(15) AUTO_INCREMENT,
       name varchar(30),
       password varchar(60),
       PRIMARY KEY (id)
)      DEFAULT CHARSET=utf8;
insert into user values(1,'Fan','Fan970506');
String name = "Fan";
String password = "fan970506";
String sql = "select * from user where name = '"+name+"' and password = '"+password+"'";
 执行查询语句,并把结果集返回给ResultSet
ResultSet rs = s.executeQuery(sql);
if(rs.next())
   System.out.println("登录成功");
else
   System.out.println("帐号或者密码错误");

获取总数

执行的sql语句为

select count(*) from hero

api文档中ResultSet 光标最初位于第一行之前,所以当查找时。next()之后才移向了第一行
然后通过ResultSet获取出来

            String sql = "select count(*) from hero";
 
            ResultSet rs = s.executeQuery(sql);
            int total = 0;
            while (rs.next()) {
                total = rs.getInt(1);
            }
 
            System.out.println("表Hero中总共有:" + total+" 条数据");

设计分页查询:

package jdbc;
 
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class JdbcQuery {
    private static final String URL = "jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8";
    private static final String DRIVER_NAME = "com.mysql.jdbc.Driver";
    private static final String USER = "root";
    private static final String PASSWORD = "admin";

    /**
     * 分页查询
     *
     * @param start 起始数
     * @param count 一页显示总数
     */
    public static void pageQuery(Statement s, int start, int count) {
        String querySql = String.format("select * from hero limit %d, %d", start, count);
        try {
            ResultSet rs = s.executeQuery(querySql);
            while (rs.next()) {
                int id = rs.getInt(1);
                String name = rs.getString(2);
                float hp = rs.getFloat(3);
                int damage = rs.getInt(4);
                System.out.printf("id:%d, name:%s, hp:%.2f, damage:%d %n", id, name, hp, damage);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        Connection c = null;
        Statement s = null;
        try {
            Class.forName(DRIVER_NAME);
            System.out.println("数据库驱动加载成功!");
        } catch (ClassNotFoundException e) {
            System.out.println("数据库驱动加载失败!");
            e.printStackTrace();
        }

        try {
/*            c  = DriverManager.getConnection(
                    "jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8",
                    "root","admin");*/
            c = DriverManager.getConnection(URL,USER,PASSWORD);
            s = c.createStatement();

            // 查询hero表中一共有多少条记录
            String sql = "select count(*) from hero";
            ResultSet rs = s.executeQuery(sql);
            int total = 0;
            if (rs.next()) {
                total = rs.getInt(1);
            }
            System.out.println("hero表中一共有" + total + "条记录");
            // 一页查询total_every_page条记录,一共可分为pages页
            int total_every_page = 3;
            int pages = (int) Math.ceil((double) total / (double) total_every_page);
            System.out.println("一共可分为" + pages + "页");
            for (int i = 0; i < pages; i++) {
                System.out.printf("查询第%d页结果:%n", i + 1);
                pageQuery(s, i * total_every_page, total_every_page);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if (s != null) {
                try {
                    s.close();
                    System.out.println("Statement已关闭");
                } catch (SQLException e) {
                    System.out.println("Statement关闭异常");
                    e.printStackTrace();
                }
            }
            if (c != null) {
                try {
                    c.close();
                    System.out.println("Connection已关闭");
                } catch (SQLException e) {
                    System.out.println("Connection关闭异常");
                    e.printStackTrace();
                }
            }
        }
    }
}

预编译statement

使用PreparedStatement

Statement一样,PreparedStatement也是用来执行sql语句的。与创建Statement不同的是,需要根据sql语句创建PreparedStatement
除此之外,还能够通过设置参数,指定相应的值,而不是Statement那样使用字符串拼接
注: 这是JAVA里唯二的基1的地方,另一个是查询语句中的ResultSet也是基1的。

package jdbc;
    
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
    
public class TestJDBC {
    public static void main(String[] args) {
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
  
        String sql = "insert into hero values(null,?,?,?)";
        try (Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8","root", "admin");
            // 根据sql语句创建PreparedStatement
            PreparedStatement ps = c.prepareStatement(sql);
        ) {
             
            // 设置参数
            ps.setString(1, "提莫");
            ps.setFloat(2, 313.0f);
            ps.setInt(3, 50);
            // 执行
            ps.execute();
  
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    
    }
}

PreparedStatement的优点1-参数设置

Statement 需要进行字符串拼接,可读性和维护性比较差

String sql = "insert into hero values(null,"+"'提莫'"+","+313.0f+","+50+")";

PreparedStatement 使用参数设置,可读性好,不易犯错

String sql = "insert into hero values(null,?,?,?)";
        String sql = "insert into hero values(null,?,?,?)";
        try (Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8","root", "admin");
            Statement s = c.createStatement();
            PreparedStatement ps = c.prepareStatement(sql);
        ) {
            // Statement需要进行字符串拼接,可读性和维修性比较差
            String sql0 = "insert into hero values(null," + "'提莫'" + "," + 313.0f + "," + 50 + ")";
            s.execute(sql0);
  
            // PreparedStatement 使用参数设置,可读性好,不易犯错
            // "insert into hero values(null,?,?,?)";
            ps.setString(1, "提莫");
            ps.setFloat(2, 313.0f);
            ps.setInt(3, 50);
            ps.execute();

PreparedStatement的优点2-性能表现

PreparedStatement有预编译机制,性能比Statement更快

        String sql = "insert into hero values(null,?,?,?)";
        try (Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8","root", "admin");
                Statement s = c.createStatement();
                PreparedStatement ps = c.prepareStatement(sql);
            ) {
            // Statement执行10次,需要10次把SQL语句传输到数据库端
            // 数据库要对每一次来的SQL语句进行编译处理
            for (int i = 0; i < 10; i++) {
                String sql0 = "insert into hero values(null," + "'提莫'" + ","
                        + 313.0f + "," + 50 + ")";
                s.execute(sql0);
            }
            s.close();
  
            // PreparedStatement 执行10次,只需要1次把SQL语句传输到数据库端
            // 数据库对带?的SQL进行预编译
  
            // 每次执行,只需要传输参数到数据库端
            // 1. 网络传输量比Statement更小
            // 2. 数据库不需要再进行编译,响应更快
            for (int i = 0; i < 10; i++) {
                ps.setString(1, "提莫");
                ps.setFloat(2, 313.0f);
                ps.setInt(3, 50);
                ps.execute();
            }

PreparedStatement的优点3-防止SQL注入式攻击

假设name是用户提交来的数据

String name = "'盖伦' OR 1=1";

使用Statement就需要进行字符串拼接
拼接出来的语句是:

select * from hero where name = '盖伦' OR 1=1

因为有OR 1=1,这是恒成立的
那么就会把所有的英雄都查出来,而不只是盖伦
如果Hero表里的数据是海量的,比如几百万条,把这个表里的数据全部查出来
会让数据库负载变高,CPU100%,内存消耗光,响应变得极其缓慢。
PreparedStatement使用的是参数设置,就不会有这个问题

        String sql = "select * from hero where name = ?";
        try (Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8","root", "admin");
                Statement s = c.createStatement();
            PreparedStatement ps = c.prepareStatement(sql);
        ) {
            // 假设name是用户提交来的数据
            String name = "'盖伦' OR 1=1";
            String sql0 = "select * from hero where name = " + name;
            // 拼接出来的SQL语句就是
            // select * from hero where name = '盖伦' OR 1=1
            // 因为有OR 1=1,所以恒成立
            // 那么就会把所有的英雄都查出来,而不只是盖伦
            // 如果Hero表里的数据是海量的,比如几百万条,把这个表里的数据全部查出来
            // 会让数据库负载变高,CPU100%,内存消耗光,响应变得极其缓慢
            System.out.println(sql0);
  
            ResultSet rs0 = s.executeQuery(sql0);
            while (rs0.next()) {
                String heroName = rs0.getString("name");
                System.out.println(heroName);
            }
  
            s.execute(sql0);
  
            // 使用预编译Statement就可以杜绝SQL注入
  
            ps.setString(1, name);
  
            ResultSet rs = ps.executeQuery();
            // 查不出数据出来
            while (rs.next()) {
                String heroName = rs.getString("name");
                System.out.println(heroName);
            }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值