Java进阶-JDBC

JDBC概述

JDBC(Java DataBase Connectivity)是Java和数据库之间的一个桥梁,是一个规范而不是一个实现,能够执行SQL语句。它由一组用Java语言编写的类和接口组成。各种不同类型的数据库都有相应的实现。

JDBC编程步骤

装载相应数据库的JDBC驱动并进行初始化
导入专用的jar包

  • 访问MySQL数据库需要用到第三方的类,这些第三方的类都被压缩在jar包里。
  • mysql-connector-java-5.0.8-bin.jar

初始化驱动

通过初始化驱动类com.mysql.jdbc.Driver

try {
        Class.forName("com.mysql.jdbc.Driver");		
        } catch (ClassNotFoundException e) { 				
            e.printStackTrace();
        }

Class.forName是把这个类加载到JVM中,加载的时候,就会执行其中的静态初始化块,完成驱动的初始化的相关工作。

建立JDBC和数据库之间的Connection连接

需要提供:

  • 数据库服务端的IP地址:127.0.0.1
  • 数据库的端口号:3306
  • 数据库名称:exam
  • 编码方式:UTF-8
  • 账号:root
  • 密码:admin

Connection c =DriverManager.getConnection(“jdbc:mysql://127.0.0.1:3306/exam?characterEncoding=UTF-8”, “root”, “admin”);

Connection是与特定数据库连接回话的接口,使用的时候需要导包,而且必须在程序结束的时候将其关闭。getConnection方法也需要捕获SQLException异常。

  • 在进行数据库的增删改查的时候都需要与数据库建立连接,所以可以在项目中将建立连接写成一个工具方法,用的时候调用即可
      /**
	 * 取得数据库的连接
	 * @return 一个数据库的连接
	 */
public static Connection getConnection(){
		Connection conn = null;
		 try {
			 	//初始化驱动类com.mysql.jdbc.Driver
	            Class.forName("com.mysql.jdbc.Driver");
	            conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/exam?characterEncoding=UTF-8","root", "admin");
	            //该类就在 mysql-connector-java-5.0.8-bin.jar中,如果忘记了第一个步骤的导包,就会抛出ClassNotFoundException
	        } catch (ClassNotFoundException e) { 				
	            e.printStackTrace();
	        }catch (SQLException e) {							
	            e.printStackTrace();
	        }
		 return conn;
	}

创建Statement或者PreparedStatement接口,执行SQL语句

使用Statement

  • Statement接口创建之后,可执行SQL语句,完成对数据库的增删改查。其中,增删改查只需改变SQL语句的内容就能完成;而查询较复杂。在Statement中使用字符串拼接的方式,该方式存在语句复杂、容易犯错等缺点。

  • Statement在实际过程中使用的非常少

  • 字符串拼接方式的SQL语句是非常繁琐的,中间有很多单引号和双引号的混用,容易出错

Statement s = conn.createStatement();
// 准备sql语句
// 注意: 字符串要用单引号'
String sql = "insert into t_courses values(null,"+"'数学')";
//在statement中使用字符串拼接的方式,这种方式存在诸多问题
s.execute(sql);
System.out.println("执行插入语句成功");

使用PreparedStatement

PreparedStatement需要根据sql语句创建

  • 使用PreparedStatement时,他的sql语句不再采用字符串拼接的方式,而是采用“ ?” 占位符的方式。这种方式除了可以避免拼接字符串的繁琐之外,还能提高性能。每次SQL语句都是一样的,java类就不会再次编译,这样能显著提高性能。

  • String sql = “update t_course set course_name =? where course_id=?”;

然后使用PreparedStatement接口中的set方法给占位符进行赋值。[索引是从1开始的]

//预编译
pstmt = (PreparedStatement) conn.prepareStatement(sql);
//利用Preparedstatement的set方法给占位符赋值
pstmt.setString(1, courseName); 
pstmt.setInt(2, courseId);
pstmt.executeUpdate();

增删改都使用pstmt.executeUpdate(); 语句进行SQL语句的提交 ,查找则使用 executeQuery() 方法

在添加的过程中,如果添加的数据比较大,可以使用批量添加。

for(int i=1;i<100;i++){
     pstmt.setInt(1,8000+i);
     pstmt.setString(2,"赵_"+i);
     pstmt.addBatch();
//批量更新
     if(i%10==0){
     pstmt.executeBatch();
    }
}

查询操作

查询表student中数据id,name

public class Ch02 {
public static void main(String[] args) throws SQLException {
        Ch02 ch02 = new Ch02();
        List<Student> stuList = ch02.findCourseList();
        System.out.println(stuList);

    }
    public List<Student> findCourseList() throws SQLException {
        String sql = "select * from stu order by id";
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        //创建集合对象存放查询到的数据
        List<Student> stuList = new ArrayList<>();


        try {
            conn = JdbcUtil.getConnection();
            pstmt = (PreparedStatement) conn.prepareStatement(sql);
            rs = (ResultSet) pstmt.executeQuery();
            while(rs.next()){
                int id = rs.getInt("id");
                String name = rs.getString("name");
                Student student = new Student(name,id);
                stuList.add(student);

            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JdbcUtil.close(conn);
            JdbcUtil.close(pstmt);
        }
        return stuList;
    }
}

class Student{
    private String name;
    private int id;

    public Student(String name, int id) {
        this.name = name;
        this.id = id;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", id=" + id +
                '}';
    }
}

处理和显示结果

执行查询语句,并把结果返回给集合ResultSet

ResultSet rs = s.executeQuery(sql);

利用While(ResultSet.net()){…}循环将ResultSet中的结果遍历出来。

ResultSet.getxxx();

  • get方法里可以填写属性值或者填写该属性在数据表中的列号

  • 一般不推荐使用列号,因为一段数据表中各个属性值顺序会发生变化

while(rs.next()){
                int id = rs.getInt("id");
                String name = rs.getString("name");
			//记录对应的对象
                Student student = new Student(name,id);
                stuList.add(student);

            }

释放资源

在JDBC编码的过程中我们创建了Connection、ResultSet等资源,这些资源在使用完毕之后是一定要进行关闭的。关闭的过程中遵循从里到外的原则。

创建工具类

为了使代码更简单,增加复用性,将一些频繁使用的操作放到一个工具类里

  • 使用反射
  • 连接数据库getConnection()
  • 释放资源close()
public class JdbcUtil {
    public static Connection getConnection() throws ClassNotFoundException, SQLException, IOException {

        Properties properties = new Properties();
        //读取外部的p文件
        properties.load(Test01.class.getClassLoader().getResourceAsStream("jdbc.properties"));
        //System.out.println(properties);
        String url = properties.getProperty("mysql.url");
        String driverName = properties.getProperty("mysql.driverName");
        String username = properties.getProperty("mysql.username");
        String password = properties.getProperty("mysql.password");

        Class clazz = Class.forName(driverName);

        Connection connection = DriverManager.getConnection(url, username, password);
        return connection;
    }

    /**
     * 封装三个关闭方法
     * @param pstmt
     */
    public static void close(PreparedStatement pstmt){
        if(pstmt != null){						//避免出现空指针异常
            try{
                pstmt.close();
            }catch(SQLException e){
                e.printStackTrace();
            }

        }
    }

    public static void close(Connection conn){
        if(conn != null){
            try {
                conn.close();
            } catch (SQLException e) {
                // TODO: handle exception
                e.printStackTrace();
            }
        }
    }

    public static void close(ResultSet rs){
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                // TODO: handle exception
                e.printStackTrace();
            }
        }
    }
    public static void close(Statement stmt){
        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                // TODO: handle exception
                e.printStackTrace();
            }
        }
    }
}

Statement和PreparedStatement的异同及优缺点

  • 同:两者都是用来执行SQL语句的

  • 异:PreparedStatement需要根据SQL语句来创建,它能够通过设置参数,指定相应的值,不是像Statement那样使用字符串拼接的方式

PreparedStatement的优点

使用参数设置,可读性好,不易记错。在statement中使用字符串拼接,可读性和维护性比较差
具有预编译机制,性能比statement更快
能够有效防止SQL注入攻击

execute和executeUpdate的区别

  • 相同点:二者都能执行增删改查

  • 不同点:

    1. execute可以执行查询语句,然后通过getResult把结果取出来。esecuteUpdate不能查询语句
    2. execute返回Boolean类型,true表示执行的是查询语句,false表示执行的insert、delete、update等。executeUpdate的返回值是int,表示有多少条数据受到了影响

案例

模拟登录功能。在前台输入用户名和密码,后台判断信息是否正确,并给出前台反馈信息,前台输出反馈信息。

  1. 创建数据库表 account 包含(aid,username,password)
  2. 开发前台代码 用户操作的页面
  3. 工具类JdbcUtil
public class Test02 {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入用户名:");
        String username = sc.next();
        System.out.println("请输入密码:");
        String password = sc.next();
        Account account = findAccount(username,password);
        System.out.println(account != null? "登录成功":"登录失败");

    }

    public static Account findAccount(String name,String pwd){
        //sql语句
        String sql = "select * from account where username = ? and password = ?";
        // 连接
        Connection conn = null;
        //执行SQL语句
        PreparedStatement pstmt = null;
        //执行查询语句,并把结果返回给集合ResultSet
        ResultSet rs = null;
        Account login = null;


        try {
            //建立连接
            conn =JdbcUtil.getConnection();
            //预编译
            pstmt = (PreparedStatement) conn.prepareStatement(sql);
            //给占位符赋值,下标是从1开始的
            pstmt.setString(1,name);
            pstmt.setString(2,pwd);
            //执行查询语句,并把结果返回给集合ResultSet
            rs = (ResultSet) pstmt.executeQuery();
            //判断是否有值
            if (rs.next()){
                login = new Account(rs.getString("username"),rs.getString("password"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JdbcUtil.close(conn);
            JdbcUtil.close(pstmt);
        }
        return login;
    }
}

class Account{
    private String username;
    private String password;

    public Account() {
    }

    public Account(String username, String password) {
        this.username = username;
        this.password = password;
    }

    @Override
    public String toString() {
        return "Account{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值