JDBC概述 JDBC(Java DataBase Connectivity)是Java和数据库之间的一个桥梁,是一个规范而不是一个实现,能够执行SQL语句。它由一组用Java语言编写的类和接口组成。各种不同类型的数据库都有相应的实现。
JDBCAPI
DriverManager驱动管理类 getConnection()获取连接
Connection接口
createStatement创建Statement对象
preparedStatement(sql)生成预处理对象
Statement接口
executeUpdate(sql)执行DML语句,返回影响的行数
executeQuery(sql)执行查询,返回ResultSet对象
execute(sql)执行任意的sql,返回boolean
PreparedStatement接口
executeUpdate(sql)执行DML语句,返回影响的行数
executeQuery(sql)执行查询,返回ResultSet对象
execute(sql)执行任意的sql,返回boolean
setObject(占位符索引,值)
Result结果集
next()向下一行移动
previous()向上移动一行
JDBC编程步骤 装载相应数据库的JDBC驱动并进行初始化 导入专用的jar包 访问MySQL数据库需要用到第三方的类,这些第三方的类都被压缩在jar包里。
mysql-connector-java-5.0.8-bin.jar
初始化驱动 通过初始化驱动类com.mysql.jdbc.Driver
1 2 3 4 5 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异常。
在进行数据库的增删改查的时候都需要与数据库建立连接,所以可以在项目中将建立连接写成一个工具方法,用的时候调用即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public static Connection getConnection () { Connection conn = null ; try { Class.forName("com.mysql.jdbc.Driver" ); conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/exam?characterEncoding=UTF-8" ,"root" , "admin" ); } catch (ClassNotFoundException e) { e.printStackTrace(); }catch (SQLException e) { e.printStackTrace(); } return conn; }
创建Statement或者PreparedStatement接口,执行SQL语句 使用Statement Statement接口创建之后,可执行SQL语句,完成对数据库的增删改查。其中,增删改查只需改变SQL语句的内容就能完成;而查询较复杂。在Statement中使用字符串拼接的方式,该方式存在语句复杂、容易犯错等缺点。
Statement在实际过程中使用的非常少
字符串拼接方式的SQL语句是非常繁琐的,中间有很多单引号和双引号的混用,容易出错
1 2 3 4 5 6 7 Statement s = conn.createStatement();String sql = "insert into t_courses values(null," +"'数学')" ;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开始的]
1 2 3 4 5 6 pstmt = (PreparedStatement) conn.prepareStatement(sql); pstmt.setString(1 , courseName); pstmt.setInt(2 , courseId); pstmt.executeUpdate();
增删改都使用pstmt.executeUpdate();语句进行SQL语句的提交 ,查找则使用executeQuery()方法
在添加的过程中,如果添加的数据比较大,可以使用批量添加。
1 2 3 4 5 6 7 8 9 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 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方法里可以填写属性值或者填写该属性在数据表中的列号
一般不推荐使用列号,因为一段数据表中各个属性值顺序会发生变化
1 2 3 4 5 6 7 8 while (rs.next()){ int id = rs.getInt("id" ); String name = rs.getString("name" ); Student student = new Student (name,id); stuList.add(student); }
ResultSet
表示数据库结果集的数据表,通常通过执行查询数据库的语句生成
ResultSet对象保持一个光标指向其当前的数据行。最初光标位于第一行之前
next方法将光标移动到下一行,并且由于在ResultSet对象中没有更多行时返回false。因此可以在while循环中使用循环来遍历结果集
在JDBC编码的过程中我们创建了Connection、ResultSet等资源,这些资源在使用完毕之后是一定要进行关闭的。关闭的过程中遵循从里到外的原则。
创建工具类 为了使代码更简单,增加复用性,将一些频繁使用的操作放到一个工具类里
使用反射
连接数据库getConnection()
释放资源close()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 public class JdbcUtil { public static Connection getConnection () throws ClassNotFoundException, SQLException, IOException { Properties properties = new Properties (); properties.load(Test01.class.getClassLoader().getResourceAsStream("jdbc.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; } 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) { e.printStackTrace(); } } } public static void close (ResultSet rs) { if (rs != null ) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } } public static void close (Statement stmt) { if (stmt != null ) { try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
Statement和PreparedStatement的异同及优缺点 同:两者都是用来执行SQL语句的
异:PreparedStatement需要根据SQL语句来创建,它能够通过设置参数,指定相应的值,不是像Statement那样使用字符串拼接的方式
PreparedStatement的优点
使用参数设置,可读性好,不易记错。在statement中使用字符串拼接,可读性和维护性比较差
具有预编译机制,性能比statement更快
能够有效防止SQL注入攻击
execute和executeUpdate的区别 相同点:二者都能执行增删改查
不同点:
execute可以执行查询语句,然后通过getResult把结果取出来。esecuteUpdate不能查询语句
execute返回Boolean类型,true表示执行的是查询语句,false表示执行的insert、delete、update等。executeUpdate的返回值是int,表示有多少条数据受到了影响
案例 模拟登录功能。在前台输入用户名和密码,后台判断信息是否正确,并给出前台反馈信息,前台输出反馈
信息。
创建数据库表 account 包含(aid,username,password)
开发前台代码 用户操作的页面
工具类JdbcUtil
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 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) { String sql = "select * from account where username = ? and password = ?" ; Connection conn = null ; PreparedStatement pstmt = null ; ResultSet rs = null ; Account login = null ; try { conn =JdbcUtil.getConnection(); pstmt = (PreparedStatement) conn.prepareStatement(sql); pstmt.setString(1 ,name); pstmt.setString(2 ,pwd); 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 + '\'' + '}' ; } }
数据库连接池 德鲁伊连接池
加入Druid jar包
加入配置文件,拷贝到src目录
创建