JDBC
//本文仅供本人学习使用,理智看待
1.持久化概述:
持久化:就是指将数据保存到可掉电式存储设备中,以供之后使用
2.什么是JDBC?存在目的意义?
JDBC是一种java访问数据库的技术,相当于一种API,我们可以通过JDBC实现对数据库的访问,而不需要自己了解各个数据库的特点自己手打访问数据库的代码,从一定程度上降低了程序员学习成本,是java唯一的访问数据库的方式
JDBC本身是一种java连接数据库的标准,是一组类和接口,具体实现就交个各个数据库厂商实现
3.JDBC使用?
1.导包:JDBC是别人封装的API,我们需要导入jar包才能使用
2.步骤:贾琏欲执事
-
1.加载数据库驱动
// 1.加载数据库驱动 Class.forName("com.mysql.jdbc.Driver");
-
2.获取连接对象
// 2.获取连接对象 con=DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb","root","123456");
-
3.获取语句对象
// 3.创建语句对象 statement = con.createStatement();
-
4.执行SQL语句
// 4.执行查询 // 传入一个sql语句并传送到数据库进行操作 String sql = "INSERT INTO student(id,name,age,score) VALUES(1,'kk',14,55D); statement.executeUpdate(sql);
-
5.释放资源(有多少个释放多少个,原则:后创建先释放)
// 5.关闭连接,后建立的先关闭 statement.close(); con.close();
3.插入操作:DML操作都是这个步骤,只需要更改SQL语句
- 贾琏欲执事;
// 1.加载数据库驱动
Class.forName("com.mysql.jdbc.Driver");
// 2.获取连接
Connection connection = JDBCUtils.getConnection();
// 3.获取语句对象
Statement statement = connection.createStatement();
// 4.书写查询语句并执行
// 需要传入一个student对象,并将其进行字符串的拼接,再将这个SQL传给数据库,这个做法很恶心,所以我么引出预编译语句,下讲
String sql = "INSERT INTO student (name,age,score) VALUES(" + "'" +student.getName() + "'" + "," + student.getAge() + "," + student.getScore() + ") ";
statement.executeUpdate(sql);
// 5.释放资源
statement.close();
connection.close();
4.预编译语句PreparedStatement:
- 设置占位符,代替字符串的拼接
// 加载注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 获取连接对象
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb","root","123456");
//创建预编译语句对象
// 编写一个带有站位符的sql,用?表示占位
String sql = "INSERT INTO student(name,age,score) VALUES(?,?,?)";
PreparedStatement ps = con.prepareStatement(sql);
// 为占位符设置值
// 注意JDBC索引都从1开始
ps.setString(1,stu.getName());
ps.setInt(2,stu.getAge());
ps.setDouble(3,stu.getScore());
// 执行SQL语句
// 注意注意注意注意注意注意!!!!!!!!!!!!!!!!!!!!!!!!
// 这里没有参数
ps.executeUpdate();
// 释放资源 (需要将建立的所有对象连接关闭,建议后开的先关闭)
ps.close();
con.close();
4.DAO(数据访问对象)思想:
-
什么是DAO思想:
DAO思想是一种规范,是java对数据库操作的规范,我们把他叫做数据持久层,首先DAO层的存在会让整个代码逻辑清楚,DAO层里面只做和访问数据库相关的事情,而不做其它的事,体现高内聚低耦合的思想.DAO层的存在大大减少了重复代码,我们在DAO层里面定义接口,规范实现类来具体实现对数据库的操作,需要操作数据库的时候只需要调用实现类的方法即可.
注意:分包规范 , 命名规范:接口以IxxxDAO命名,实现类xxxDAOImpl ,
采取面向接口的思想
测试先行
5.DQL查询操作:
-
1.ResultSet:结果集
-
2.实现查询:
public List<Student> selectAll() { Connection con = null; ResultSet rs = null; PreparedStatement ps = null; try { // 获取连接 con = JDBCUtil.getConnection(); // 创建语句对象 String sql = "SELECT * FROM student"; ps = con.prepareStatement(sql); // 指定sql语句返回一个结果集 rs = ps.executeQuery(); // 从结果集里拿到数据封装到student对象里面 List<Student> list = new ArrayList<>(); while (rs.next()) { long id = rs.getLong("id"); String name = rs.getString("name"); int age = rs.getInt("age"); double score = rs.getDouble("score"); Student stu = new Student(id,name,age,score); list.add(stu); } return list; } catch (SQLException e) { e.printStackTrace(); } finally { // 关闭资源 JDBCUtil.close(rs,ps,con); } return null; }
6.JDBCUtil工具类:
-
抽取重复的代码,放在util包下面,需要时调用,减少重复代码
public class JDBCUtil { // 私有化构造器防止外界通过构造器创建对象 private JDBCUtil(){}; private static Properties p = null; static { // 通过配置文件拿到数据 // 解决硬编码 try { p = new Properties(); // 类加载器 ClassLoader loader = Thread.currentThread().getContextClassLoader(); InputStream in = loader.getResourceAsStream("db.properties"); p.load(in); Class.forName(p.getProperty("driverClassName")); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } // 获取连接对象 public static Connection getConnection() { // 2.获取连接对象 Connection con = null; try { con = DriverManager.getConnection(p.getProperty("url"),p.getProperty("username"),p.getProperty("password")); } catch (SQLException e) { e.printStackTrace(); } return con; } // 释放资源 public static void close(ResultSet rs, Statement ps, Connection con) { // 5.释放资源 try { if (rs != null) { rs.close(); } } catch (SQLException e) { e.printStackTrace(); } try { if (ps != null) { ps.close(); } } catch (SQLException e) { e.printStackTrace(); } try { if (con != null) { con.close(); } } catch (SQLException e) { e.printStackTrace(); } } }
7.事务:
-
(1).什么是事务?以及使用事务的必要性:
-
事务是一组逻辑操作单元,在程序中,没有事务是一件很恐怖的事情,事务具有四大特性:ACID(下讲),这四个特性中的原子性保证了事务是一个不可分割的单元,里面的代码要么一起执行,要么都不执行.在实际开发过程中,许多情况下都需要保证数据的完整性,保证数据不被破坏可以用到事务.例如再执行转账操作的时候,我们需要从第一个人的账号上减去一部分金额加到第二个人的账户上,若在这两个操作中发生了异常(网络延迟或者是停电关机等)造成程序异常中断,第二个操作未执行到,就会造成数据被破坏,因此使用事务是一件很有必要的事情,他可以保证数据的完整性
-
查询操作是没有风险的
-
风险发生在增删改上
-
对单行记录的增删改一般没有风险,风险发生在对多行记录同时操作
只有innodb存储引擎支持提交事务,myISAM不支持
(2):ACID属性:
原子性:事务是一个不可分割的整体
一致性:保证数据的一致,数据从一个完整的状态装换到另一个完整的状态
隔离性:一个事务的执行不被另一个事务所影响
持久性:数据一旦被修改(事务一旦提交不能回滚)不能回滚到事务开始的状态
(3):事务的使用:
try { Connection对象.setAutoCommit(false); //操作1 //操作2 //异常 //操作3 ... //手动提交事务 Connection对象.commit(); } catch (Exception e){ //处理异常 //回滚事务 Connection对象.rollback(); }
-
8.连接池:
-
合理的高效的使用连接对象,我们学习的阿里巴巴的Druid
-
8.1:什么是连接池:
连接池是一个存放了很多个连接对象的集合,若出现一时间内有多个用户(成百上千个)访问数据库,可能会造成服务器崩溃,因为频繁地和数据库获取连接是很耗费资源的,但我们也不能采取获取连接后不释放资源的方式来解决这个问题,因为不释放资源可能造成数据丢失,那么我们就引出了连接池这个概念.
事先创建好一定数量的Collection(或其子类)对象,并将其放在连接池里面,当有用户访问数据库,需要取得连接的时候就在连接池里拿到这个连接对象,而不需要我们自己去创建连接,在用完之后再将这个连接返还给连接池.
-
8.2使用:
@Test public void testDataSource() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); dataSource.setUrl("jdbc:mysql:///mydb"); dataSource.setUsername("root"); dataSource.setPassword("123456"); dataSource.setInitialSize(5); dataSource.setMaxActive(10); dataSource.setMinIdle(2); // 连接池的四大基本属性 /* ds.setDriverClassName("com.mysql.jdbc.Driver"); ds.setUrl("jdbc:mysql:///mydb"); ds.setUsername("root"); ds.setPassword("123456"); ds.setInitialSize(5); ds.setMaxActive(10); ds.setMinIdle(2);*/ // 通过工厂类创建连接池对象 // 直接将加载好的Properties对象传递给对应的方法 // 底层一样的通过上面的代码完成我们的属性设置 // 怎样才能保证我们的工厂类成功的取到我们的数据 // 约定:db.properties的命名规范 // 规定的一个内容,key和DruidDataSource对象中的属性名一致 //ds = DruidDataSourceFactory.createDataSource(p);在此处传递一个Properties 对象,底层自动给属性设置值 Connection con = null; try { // 返回的是一个DruidPooledConnection对象 con = dataSource.getConnection(); } catch (SQLException e) { e.printStackTrace(); } System.out.println(con.getClass()); }
9.Statement和PreparedStatement的区别:
- PreparedStatement效率更高(但mysql不支持),
- 能够防止sql注入,因为先判断sql结构
- 避免繁琐的恶心的sql拼接