JDBC
JDBC
- Java数据库连接,(Java Database Connectivity,简称JDBC)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。JDBC也是Sun Microsystems的商标。我们通常说的JDBC是面向关系型数据库的。
- 本质:其实是官方定义的一套操作所有关系型数据库的规则,即接口。各个数据库厂商去实现这套接口,提供数据库驱动jar包我们可以使用这套接口(JDBC)编程,真正执行的代码时驱动jar包中的实现类
数据库驱动
- 驱动:两个设备(应用)之间的通信桥梁
快速入门
步骤
- 导入驱动jar包
- 复制jar包到项目的libs目录下
- 项目点右键—>Add as Libr
- 注册驱动
- 获取数据库链接对象
- 定义sql
- 获取执行sql语句的对象 Statement
- 执行sql,接受返回结果
- 处理结果
- 释放资源
代码示例
//注册驱动
Class.forName("com.mysql.jdbc.Driver");
//获取数据库连接对象
Connection conn = DriverManager.getConnection
("jdbc:mysql://localhost:3306/root", "root","root");
//定义sql语句
String sql = "update student set socre = 100 where sid = 2";
//获取执行sql的对象 Statement
Statement stmt = conn.createStatement();
//执行sql
int count = stmt.executeUpdate(sql);
//处理结果
System.out.println(count);
//释放资源
stmt.close();
conn.close();
详解各个对象
DriverManager:驱动管理对象
-
功能:
-
注册驱动
-
static void registerDriver(Driver driver) :注册给定的驱动程序 DriverManager。
-
写代码使用:Class.forName(“com.mysql.jdbc.Driver”);
通过查看源码发现com.mysql.jdbc.Driver类中存在静态代码块static { try { java.sql.DriverManager.registerDriver(new Driver()); } catch (SQLException E) { throw new RuntimeException("Can't register driver!"); } } -
mysql5之后的jar包可以胜率注册驱动的步骤
-
-
获取数据库连接:
- 方法
- static Connection getConnection(String url, String user,String password);
- 参数:
- url:指定的连接路径
- 语法:jdbc:mysql://ip地址(域名):端口号/数据库名称
- 示例:“jdbc:mysql://localhost:3306/root”
- 细节:如果连接本机的mysql服务器,并且mysql服务默认端口为3306,则url可以简写为"jdbc:mysql:///root"
- user:用户名
- password:密码
- url:指定的连接路径
- 方法
-
Connection:数据库连接对象
-
功能
- 获取执行sql对象
- Statement createStatement()
- PreparedStatement prepareStatement(String sql)
- 管理事务
- 开启事务:setAutoCommit(boolean autoCommit):调用该方法设置参数为false,即开启事务
- 提交事务:commit()
- 回滚事务:rollback()
- 获取执行sql对象
Statement:执行sql对象
- 执行sql
- boolean execute(String sql):可以执行任意的sql 了解
- int executeUpdate(String sql):执行DML(insert、update、delete)语句、DDL(create, alter, drop)语句
- 返回值:影响的行数,可以通过这个影响的行数判断DML语句是否执行成功,返回值>0 则执行成功,反之,则失败。
- ResultSet executeQuery(String sql):执行DQL(select)语句
ResultSet:结果集对象,封装查询结果
-
next():游标向下移动一行
-
getXxx(参数):获取数据
-
Xxx:代表数据类型 如:int getInt(),String getString();
-
参数:
- int:代表列的编号,从1开始 如:getInt(1)
- String:代表列名称 。 如:getDouble(“balance”)
-
注意:
-
使用步骤
-
游标向下移动一行
-
判断是否有数据
-
获取数据
while(rs.next()){ //获取数据 int id = rs.getInt(1); String name = rs.getString("name"); double balance = rs.getDouble(3); System.out.println(id + " " + name + " " + balance); }
-
-
-
preparedStatement:
- SQL注入问题:在拼接sql时,有一些sql的特殊关键字参与字符串的拼接。会造成安全性问题
- 属于用户随便,输入密码:a’ or ‘a’ = 'a
- sql: select * from user where username = ‘张三’ AND password = ‘a’ or ‘a’ = ‘a’
- 解决sql注入问题:使用PrepareStatement对象来解决
- 预编译sql:参数使用?作为占位符
- 步骤:
- 导入驱动jar包
- 注册驱动
- 获取数据库链接对象
- 定义sql
- 注意:sql的参数使用?(英文)作为占位符
- 示例:select * from user where username = ? AND password = ?;
- 获取执行sql语句的对象 Preparetatement Connection.prepareStatement(String sql)
- 给?赋值:
- 方法:setXxx(参数1,参数2)
- 参数1:?的位置编号从1开始
- 参数2:?的值
- 方法:setXxx(参数1,参数2)
- 执行sql,接受返回结果,不需要传递sql语句
- 处理结果
- 释放资源
抽取JDBC工具类:JDBCUtils
-
简化书写
-
分析:
- 注册驱动抽取
- 抽取获取连接对象方法
- 需求:不想传递参数,还得保证工具类的通用性
- 解决:配置文件
jdbc.properties- url =
- user =
- password =
- 抽取一个方法释放资源
-
代码示例:
package ash.utils; import java.io.FileReader; import java.io.IOException; import java.net.URL; import java.sql.*; import java.util.Properties; public class JDBCUtils { private static String url; private static String user; private static String password; private static String driver; static { try { //创建properties集合类 Properties pro = new Properties(); //获取src路径下文件的方式 ---->ClassLoader(); ClassLoader classloader = JDBCUtils.class.getClassLoader(); URL res = classloader.getResource("jdbc"); String path = res.getPath(); System.out.println(path); //加载文件 pro.load(new FileReader(path)); //获取数据 url = pro.getProperty("url"); user = pro.getProperty("user"); password = pro.getProperty("password"); driver = pro.getProperty("driver"); //注册驱动 Class.forName(driver); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(url,user,password); } public static void close(Statement stmt, Connection conn){ if(stmt != null){ try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } } if(conn != null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } public static void close(Statement stmt, Connection conn, ResultSet res){ if(res != null){ try { res.close(); } catch (SQLException e) { e.printStackTrace(); } } if(stmt != null){ try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } } if(conn != null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
JDBC控制事务:
事务:
一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败
操作:
- 开启事务
- 提交事务
- 回滚事务
使用Connection对象来管理事务
- 开启事务:setAutoCommit(boolean autoCommit):调用该方法设置参数为false,即开启事务
- 在执行sql之前开启事务
- 提交事务:commit()
- 当所有sql都执行完提交事务
- 回滚事务:rollback()
- 在catch中回滚事务
数据库连接池
概念
就是一个容器(集合),存放数据库连接的容器
当系统初始化好后,容器被创建,容器会申请一些连接对象,当用户来访问数据库时,当用户来访问数据时,从容器中获取连接对象,用户访问完后,会将连接对象归还给容器
好处
- 节约资源
- 用户访问高效
实现
- 标准接口:DataSource javax.sql包下的
- 方法:
- 获取连接:getConnection()
- 归还连接:Connection.close()、如果对象Connection时从连接池中获取的,那么调用Connection.close()方、则不会再关闭连接,而是归还连接
- 一般我们不去实现它,有数据库厂商来实现
- C3P0:数据库连接池技术
- Druid:数据库连接池实现技术,由阿里巴巴提供的
- 方法:
C3P0:数据库连接池技术
- 步骤:
- 导入jar包(两个)
- c3p0-0.9.5.2.jar mchangej-commons-java-0.2.12.jar
- 不要忘记导入数据库驱动jar包
- 定义配置文件
- 名称:c3p0.properties 或者 c3p0-config.xml
- 路径:直接将文件放在src目录下即可
- 创建核心对象:数据库连接池对象 ComboPoolDataSource
- 获取连接:getConnection
- 导入jar包(两个)
Druid:数据库连接池使用技术,有阿里巴巴提供
-
步骤:
- 导入jar包 druid-1.0.9.jar
- 定义配置文件
- 是properties形式存在的
- 可以叫任意名称,可以放在任意目录下
- 加载配置文件:Properties
- 获取数据库连接池对象:通过工厂来获取 DruidDataSourceFactory
- 获取连接:getConnection
-
定义工具类
-
定义一个类 JDBCUtils
-
提供静态代码块加载配置文件,初始化连接池对象
-
提供一个方法:
- 获取连接池:通过数据库连接池获取连接
- 释放资源
- 获取连接池的方法
-
代码示例
package com.ash.utils; import com.alibaba.druid.pool.DruidDataSourceFactory; import javax.sql.DataSource; import java.io.IOException; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Properties; public class JDBCUtils { private static Properties pro = new Properties(); private static DataSource ds = null; static { try { pro.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties")); ds = DruidDataSourceFactory.createDataSource(pro); } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { return ds.getConnection(); } public static DataSource getDataSource(){ return ds; } public static void close(Statement stmt, Connection conn){ if(stmt != null){ try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } } if(conn != null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } public static void close(ResultSet res, Statement stmt, Connection conn){ if(res != null){ try { res.close(); } catch (SQLException e) { e.printStackTrace(); } } close(stmt, conn); } }
-
Spring JDBC
Spring 框架对JDBC的简单封装
提供了一个JDBCTemplate对象简化JDBC的开发
-
步骤
- 导入jar包
- 创建JDBCTemplate对象。依赖于数据源DataSource
- jdbcTemplate template = new jdbcTemplate(ds);
- 调用jdbcTemplate的方法来完成CRUD的操作
- update():执行DML语句。增、删、改、查语句
- queryForMap():查询结果,将结果封装为map集合,将列名作为key,将值作为value将这条记录封装为一个map集合
- 注意:这个方法查询的结果集长度只能为1
- queryForList():查询结果,将结果封装为list集合
- 注意:将每一条记录封装为Map集合,再将Map集合装载到list集合中
- query() :查询结果,将结果封装为JavaBean对象
- query的参数:RowMapper
- 一般我们使用BeanPropertyRowMapper实现类。可以完成数据到JavaBean的自动封装
- 如果自己实现RowMapper则,JavaBean的类属性要用封装类型
- 避免出现Nul的赋值异常
- new BeanPropertyRowMapper<类型>(类型.class)
- query的参数:RowMapper
- queryForObject:查询结果,将结果封装为对象
- 一般用于聚合函数的查询
-
代码示例:
/** * 更改学生表内id为1的分数为100 */ @Test public void sss(){ String sql = "Update student set score = 100 where sid = ?"; int count = template.update(sql, 1); System.out.println(count); } /** *在学生表中添加一条记录 */ @Test public void test2(){ String sql = "insert into student(sid,name,age,score) values (?,?,?,?) "; int count = template.update(sql, null, "赵六", 17, 75); System.out.println(count); } /** * 删除一条记录 */ @Test public void test3(){ String sql = "delete from student where sid = ? "; template.update(sql,4); } /** * 查询id为1的记录,封装为map集合 */ @Test public void test4(){ String sql = "select *from student where sid = ?"; Map<String, Object> res = template.queryForMap(sql,1); System.out.println(res); } /** * 查询所有记录封装为list */ @Test public void test5(){ String sql = "select * from student"; List<Map<String, Object>> maps = template.queryForList(sql); for (Map<String, Object> map : maps) { System.out.println(map); } } /** * 查询所有记录封装为Student对象---自己实现方法 */ @Test public void test6(){ String sql = "select * from student"; List<Student> list = template.query(sql, new RowMapper<Student>() { @Override public Student mapRow(ResultSet res, int i) throws SQLException { Student s = new Student(); s.setAge(res.getInt("age")); s.setName(res.getString("name")); s.setScore(res.getDouble("score")); s.setSid(res.getInt("sid")); return s; } }); for (Student s : list) { System.out.println(s.getSid() + s.getName() + s.getAge() +s.getScore()); } } /** * 查询所有记录封装为Student对象---使用提供的实现方法 */ @Test public void test6(){ String sql = "select * from student"; List<Student> list = template.query(sql, new BeanPropertyRowMapper<Student>(Student.class)); for (Student s : list) { System.out.println(s.getSid() + s.getName() + s.getAge() +s.getScore()); } } /** * 查询总记录数 */ @Test public void test7(){ String sql = "select count(*) from student"; Long total = template.queryForObject(sql, Long.class); System.out.println(total); }
3047

被折叠的 条评论
为什么被折叠?



