1 JDBC(Java Database Connectivity)
1.1 JDBC概念
JDBC(Java Database Connectivity) Java 连接数据库的规范(标准),可以使用 Java 语言连接数据库完成 CRUD 操作
1.2 JDBC 核心思想
Java 中定义了访问数据库的接口,可以为多种关系型数据库提供统一的访问方式。由数据库厂商提供驱动实现类(Driver 数据库驱动)。
JDBC核心思想 2 JDBC开发步骤
/** * JDBC的开发步骤: * 0、准备工作 * a、准备数据库和数据表 * b、导入jar包 * 1、在工程下新建一个lib的文件,将驱动jar包放入到文件夹中 * 2、右击jar包---> add as library * 注意:类路径(classpath) 就是java代码生成.class文件的路径 * 1、注册驱动 * 2、获取数据库连接对象Connection * 3、获取数据库操作对象 * 4、通过数据库操作对象执行SQL语句 * 5、处理结果 * 6、释放资源 */
2.0 环境准备
环境准备
- a、将数据库连接驱动包赋值到当前工程的lib文件夹下
- b、将jar包添加到类路径(class文件生成的位置)中。右击jar包 —> add as library
2.1 注册数据库驱动
//1、注册数据库驱动 //实现方式一:不推荐使用 //Driver driver = new Driver(); //DriverManager.registerDriver(driver); //实现方式二:推荐使用 Class.forName("com.mysql.jdbc.Driver");//主动触发类加载,执行静态代码块,进而注册驱动
2.2 获取数据库的连接
协议://地址:端口号
- mysql 5.7版本 jdbc:mysql://localhost:3306/数据库名
- mysql 8.x版本 需要加上指定时区 jdbc:mysql://localhost:3306/数据库名?serverTimezone=?serverTimezone = UTC (北京时间)
- jdbc:mysql://localhost:3306/数据库名?serverTimezone=?serverTimezone = Asia/shanghai (j精确到时分秒时间)
- 本机数据库localhost:3306可以省略不写,即 jdbc:mysql:///数据库名
// 2、获取数据库连接对象Connection /** * 网络编程三要素 * 协议+地址+端口 * jdbc:mysql://localhost:3306/数据库名?serverTimezone=UTC */ Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/java2303", "root", "123456");
2.3 获取数据库操作对象Statement
// 3、获取数据库操作对象 Statement statement = conn.createStatement();
2.4 通过Statement对象执行SQL语句
// 4、通过数据库操作对象执行SQL语句 int count = statement.executeUpdate( "insert into emp (empno,ename,job,mgr,hiredate,sal,comm,deptno) values (6666,'张三','java',7369,'2021-05-01',30000,200,30)");
2.5 处理返回结果
// 5、处理结果 if(count > 0){ System.out.println("插入成功!!"); }else{ System.out.println("插入失败!!"); }
2.6 释放资源
//6、释放资源 statement.close(); conn.close();
3 ResultSet结果集
//5、处理结果集 /** * ResultSet提供了一组方法 * next(); 判断是否有下一行数据,如果有返回true,并将游标移动到下一行 * getXXX("字段名"); XXX表示字段在java中的对应的类型 * getXXX(列的下标); XXX表示字段在java中的对应的类型 */
3.1 查询案例
查询emp表的数据
while(rs.next()){ int empno = rs.getInt("empno"); //int empno = rs.getInt(1); System.out.println(empno); String ename = rs.getString("ename"); System.out.println(ename); String job = rs.getString("job"); System.out.println(job); Date hiredate = rs.getDate("hiredate"); System.out.println(hiredate); double sal = rs.getDouble("sal"); System.out.println(sal); }
四、综合案例【登录】
4.1 登录分析
/** * 登录的思路: * 1、根据用户输入的用户名和密码到数据库中查询 * select * from tb_user where username = "你输入的用户名" and password = "你输入的密码" * select * from tb_user where username = admin and password = 123 * 如果有结果:登录成功 * 如果没有结果:登录失败 */
4.2 登录案例实现
public class JDBCDemo05 { public static void main(String[] args) throws Exception { Scanner sc = new Scanner(System.in); System.out.println("请输入用户名"); String username = sc.nextLine(); System.out.println("请输入密码"); String password = sc.nextLine(); Class.forName("com.mysql.jdbc.Driver"); Connection conn = DriverManager.getConnection("jdbc:mysql:///java2303", "root", "123456"); Statement statement = conn.createStatement(); String sql = " select * from tb_user where username = '" + username + "' and password = '" + password +"'"; System.out.println(sql); ResultSet rs = statement.executeQuery(sql); if(rs.next()){ //登录成功 System.out.println("登录成功"); }else{ //登录失败 System.out.println("登录失败"); } rs.close(); statement.close(); conn.close(); } }
4.3 登录案例分析-SQL注入问题
以上代码会出现SQL注入问题
- 用户输入的数据中有 SQL 关键字或语法并且参与了 SQL 语句的编译,导致 SQL 语句编译后的条件含义为 true,一直得到正确的结果。这种现象称为 SQL 注入。
- 字符串的拼接操作也是非常的不方便
4.4 登录案例更新
public class JDBCDemo06 { public static void main(String[] args) throws Exception { Scanner sc = new Scanner(System.in); System.out.println("请输入用户名"); String username = sc.nextLine(); System.out.println("请输入密码"); String password = sc.nextLine(); Class.forName("com.mysql.jdbc.Driver"); Connection conn = DriverManager.getConnection("jdbc:mysql:///java2303", "root", "123456"); //3、获取数据库操作对象PreparedStatement 预加载SQL语句 PreparedStatement ps = conn.prepareStatement("select * from tb_user where username = ? and password = ?"); //3.1 设置占位符的值 /** * PreparedStatement对象中提供了一组方法 * setXXX(index从1开始,要传入的值) XXX表示对应的java类型 */ ps.setString(1,username); ps.setString(2,password); System.out.println(ps); //4、执行SQL语句 ResultSet rs = ps.executeQuery(); if(rs.next()){ //登录成功 System.out.println("登录成功"); }else{ //登录失败 System.out.println("登录失败"); } rs.close(); ps.close(); conn.close(); } }
4.5 PreparedStatement
PreparedStatement 继承了 Statement 接口,执行 SQL 语句的方法无异。
作用:
- 预编译SQL 语句,效率高。
- 安全,避免SQL注入
五、ORM映射
5.1 思想
ORM (Object Relational Mapping)
将数据库中的表的数据,一行一行的映射到Java对象中
ORM思想 |
|
5.2 实体类的规范
JavaBean设计规范
1、类名与表名一致,属性名和字段名一致
2、私有化属性对外提供set、get方法
3、提供有参和无参构造
4、基本数据类型要使用包装类(默认值)
5、在需要的时候实现序列化接口
5.3 代码实现
查询
public class JDBCDemo04 { public static void main(String[] args) throws Exception { //1、注册驱动 Class.forName("com.mysql.jdbc.Driver"); //2、获取数据库连接对象 Connection conn = DriverManager.getConnection("jdbc:mysql:///java2303", "root", "123456"); //3、获取数据库操作对象 Statement statement = conn.createStatement(); //4、执行SQL语句 ResultSet rs = statement.executeQuery("select * from emp"); //5、处理结果集 //定义List集合保存所有的emp对象 List<Emp> empList = new ArrayList<>(); while(rs.next()){ int empno = rs.getInt("empno"); String ename = rs.getString("ename"); String job = rs.getString("job"); int mgr = rs.getInt("mgr"); Date hiredate = rs.getDate("hiredate"); double sal = rs.getDouble("sal"); double comm = rs.getDouble("comm"); int deptno = rs.getInt("deptno"); //将查询的结果存放到Emp对象中 Emp emp = new Emp(empno,ename,job,mgr,hiredate,sal,comm,deptno); //将Emp对象添加到List中 empList.add(emp); } //遍历集合中所有元素 empList.forEach(System.out::println); // for(Emp emp : empList){ // System.out.println(emp); // } //6、释放资源 rs.close(); statement.close(); conn.close(); } }
6 封装工具类
1、注册数据库驱动(静态代码块)
2、获取数据库连接 (方法:getConnection)
3、释放资源 (方法:closeAll(Connection , Statement , ResultSet ))
4、将配置信息放到properties配置文件中,减少硬编码
6.1 代码实现
工具类代码
/** * 数据库工具类 */ public class JDBCUtils { /** * 1、注册驱动(只需要注册一次) * 可以将注册驱动的代码写到静态代码块中 * 2、获取数据库连接 * 提供静态一个方法,用于返回数据库连接对象 * 3、关闭资源 * 提供静态一个方法,用于释放资源 * 4、硬编码问题(.xml .properties) * 将数据源信息保存到配置文件中,然后在代码中进行读取 * properties文件的格式:key和value都是String类型 * key=value */ private static String driver; private static String url; private static String username; private static String password; static{ try { //读取配置文件 Properties properties = new Properties(); //通过类对象读取当前类路径下的资源 InputStream in = JDBCUtils.class.getClassLoader().getResourceAsStream("db.properties"); //将配置文件中的信息读取到Properties集合中 properties.load(in); //从集合中取出数据 driver = properties.getProperty("driver123"); url = properties.getProperty("url"); username = properties.getProperty("username"); password = properties.getProperty("password"); //注册驱动 Class.forName(driver); } catch (Exception e) { e.printStackTrace(); } } public static Connection getConnection(){ Connection conn = null; try { conn = DriverManager.getConnection(url,username,password); } catch (SQLException throwables) { throwables.printStackTrace(); } return conn; } public static void closeAll(Connection conn, Statement statement, ResultSet rs){ try { if(rs!=null) rs.close(); if(statement != null) statement.close(); if(conn != null) conn.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } }
编写配置文件properties (集合工具类-自己补充)
- 在src更目录下创建xx.properties的new file
- 集合键值对 driver = com.mysql.jdbc.Driver url = username = password =
- 在静态代码块读取配置文件
- 创建properties对象
配置文件 db.properties
driver123=com.mysql.jdbc.Driver url=jdbc:mysql:///java2303 username=root password=123456
6.2 工具类测试
public class JDBCDemo01 { public static void main(String[] args) throws SQLException { //2、获取数据库连接 Connection conn = JDBCUtils.getConnection(); //3、获取数据库操作对象 PreparedStatement ps = conn.prepareStatement("select * from emp"); //4、执行SQL语句 ResultSet rs = ps.executeQuery(); //5、处理结果集 while(rs.next()){ int empno = rs.getInt("empno"); String ename = rs.getString("ename"); String job = rs.getString("job"); int mgr = rs.getInt("mgr"); Date hiredate = rs.getDate("hiredate"); double sal = rs.getDouble("sal"); double comm = rs.getDouble("comm"); int deptno = rs.getInt("deptno"); System.out.println(ename); } //6、释放资源 JDBCUtils.closeAll(conn,ps,rs); } }
7 DAO (Data Access Object)
DAO 实现了业务逻辑与数据库访问相分离。
- 对同一张表的所有操作封装在XxxDaoImpl对象中。
- 根据增删改查的不同功能实现具体的方法(insert、update、delete、select、selectAll)。
7.1 开发流程
7.1.1 EmpDao接口
public interface EmpDao { //增加员工 int insertEmp(Emp emp) throws SQLException; //删除员工 int deleteEmp(int empno); //修改员工 int updateEmp(Emp emp) throws SQLException; //查询所有员工 List<Emp> selectAll() throws SQLException; //查询单个员工 Emp selectOne(int empno); }
7.1.2 实体类
com.qf.pojo包下创建实体类
public class Emp { private Integer empno; private String ename; private String job; private Integer mgr; private Date hiredate; private Double sal; private Double comm; private Integer deptno; //省略get、set、构造方法 }
7.1.3 EmpDao实现类
public class EmpDaoImpl implements EmpDao { @Override public int insertEmp(Emp emp) throws SQLException { //2、获取数据库连接对象 Connection conn = JDBCUtils.getConnection(); //3、获取数据库操作对象 PreparedStatement ps = conn.prepareStatement("insert into emp values(?,?,?,?,?,?,?,?)"); //3.1设置占位符的值 ps.setInt(1,emp.getEmpno()); ps.setString(2,emp.getEname()); ps.setString(3,emp.getJob()); ps.setInt(4,emp.getMgr()); //将util.date 转换成 sql.date ps.setDate(5,new Date(emp.getHireadate().getTime())); ps.setDouble(6,emp.getSal()); ps.setDouble(7,emp.getComm()); ps.setInt(8,emp.getDeptno()); //4、执行SQL语句 int count = ps.executeUpdate(); //5、处理结果 //6、释放资源 JDBCUtils.closeAll(conn,ps,null); return count; } @Override public int deleteEmp(int empno) { return 0; } @Override public int updateEmp(Emp emp) throws SQLException { //2、获取数据库连接对象 Connection conn = JDBCUtils.getConnection(); //3、获取数据库操作对象 PreparedStatement ps = conn.prepareStatement("update emp set ename=?,job=?,mgr=?,hiredate=?,sal=?,comm=?,deptno=? where empno = ?"); //3.1设置占位符的值 ps.setString(1,emp.getEname()); ps.setString(2,emp.getJob()); ps.setInt(3,emp.getMgr()); //将util.date 转换成 sql.date ps.setDate(4,new Date(emp.getHireadate().getTime())); ps.setDouble(5,emp.getSal()); ps.setDouble(6,emp.getComm()); ps.setInt(7,emp.getDeptno()); ps.setInt(8,emp.getEmpno()); //4、执行SQL语句 int count = ps.executeUpdate(); //5、处理结果 //6、释放资源 JDBCUtils.closeAll(conn,ps,null); return count; } @Override public List<Emp> selectAll() throws SQLException { //2、获取数据库连接对象 Connection conn = JDBCUtils.getConnection(); //3、获取数据库操作对象 PreparedStatement ps = conn.prepareStatement("select * from emp"); //4、执行SQL语句 ResultSet rs = ps.executeQuery(); //5、处理结果集 List<Emp> empList = new ArrayList<>(); while(rs.next()){ int empno = rs.getInt("empno"); String ename = rs.getString("ename"); String job = rs.getString("job"); int mgr = rs.getInt("mgr"); Date hiredate = rs.getDate("hiredate"); double sal = rs.getDouble("sal"); double comm = rs.getDouble("comm"); int deptno = rs.getInt("deptno"); //将查询的结果存放到Emp对象中 Emp emp = new Emp(empno,ename,job,mgr,hiredate,sal,comm,deptno); //将Emp对象添加到List中 empList.add(emp); } //6、释放资源 JDBCUtils.closeAll(conn,ps,rs); return empList; } @Override public Emp selectOne(int empno) { return null; } }
7.1.4 测试类
public class TestEmpDao { public static void main(String[] args) throws Exception { //测试查询所有 // EmpDao empDao = new EmpDaoImpl(); // List<Emp> empList = empDao.selectAll(); // System.out.println(empList); //测试增加 // EmpDao empDao = new EmpDaoImpl(); // Emp emp = new Emp(9000,"韩梅梅","mysql",7369,new Date(),4000d,200d,30); // System.out.println(empDao.insertEmp(emp)); //测试修改 EmpDao empDao = new EmpDaoImpl(); Emp emp = new Emp(9000,"李雷","java",7369,new Date(),40000d,200d,30); System.out.println(empDao.updateEmp(emp)); } }
Java数据库部分(MySQL+JDBC)(二、JDBC超详细学习笔记)(下):https://developer.aliyun.com/article/1580599