一. 引言

1.1 如何操作数据库

  • 使用客户端工具访问数据库, 需要手工建立连接, 输入用户名和密码登陆, 编写SQL语句, 点击执行, 查看操作结果(结果集或受行数影响)

1.2 实际开发中, 会采用客户端操作数据库吗?

  • 在实际开发中, 当用户的数据发生改变时, 不可能通过客户端操作执行SQL语句, 因为操作量过大, 无法保证效率和正确性

二. JDBC

2.1 什么是JDBC?

  • JDBC(Java Database Connectivity) Java连接数据库, 可以使用Java语言连接数据库完成CRUD操作

2.2 JDBC核心思想

  • Java中定义了访问数据库的接口, 可以为多种关系型数据库提供统一的访问方式. 由数据库厂商提供驱动实现类(Driver数据库驱动)
2.2.1 MySQL数据库驱动
  • mysql-connector-java-5.1.X-bin.jar: 适用于5.X版本
  • mysql-connector-java-8.0.X-bin.jar: 适用于8.X版本
  • 下载链接:
2.2.2 JDBC API
  • JDBC是由多个接口和类进行功能实现
类型 权限定名 简介
class java.sql.DriverManager 管理多个数据库驱动类, 提供了获取数据库连接的方法
interface java.sql.Connection 代表一个数据库连接(当Connection不是null时, 表示已连接数据库)
interface java.sql.Statement 发送SQL语句到数据库工具
interface java.sql.ResultSet 保存SQL查询语句的结果数据(结果集)
class java.sql.SQLException 处理数据库应用程序时所发生的异常

2.3 环境搭建

  1. 在项目下新建lib文件夹,用于存放jar文件
  2. 将mysql驱动mysql-connector-java-5.1.X-bin.jar复制到项目中的lib文件夹中
  3. 选中lib文件夹右键Add as Library, 点击OK

三. JDBC开发步骤[重点]

3.1 注册驱动

  • 使用class.forName("com.mysql.jdbc.Driver");手动加载字节码文件到 JVM 中
  1. Class.forName("com.mysql.jdbc.Driver");//加载驱动

3.2 连接数据库

  • 通过DriverManager.getConection(url, user, password)获取数据库连接对象

    • URL: jdbc: msql: //localhost: 3306/database
    • username: root
    • password: root
  1. Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/database?useUnicode=true&characterEncoding=utf8", "root", "root");
  • URL(Union Resource Location) 统一资源定位符: 由协议, IP, 端口, SID(程序实例名称)组成

3.3 获取发送SQL的对象

  • 通过Connection对象获得Statement对象, 用于对数据库进行通用访问
  1. Statement statement = conn.createStatement();

3.4 执行SQL语句

  • 执行SQL语句并接收执行结果
  1. String sql = "insert into t_jobs(job_id,job_title,min_salary,max_salary) values('JAVA_Mgr','JAVA_Manager',4000,10000)";
  2. int result = statement.executeUpdate(sql);//执行SQL语句并接收结果
  • 注意: 在编写DML语句时, 一定要注意字符串参数的符号是单引号'值'
  • DML语句: 增删改时, 返回受影响的行数(int 类型)
  • DQL语句: 查询时, 返回结果数据(ResultSet结果集)

3.5 处理结果

  • 接收处理操作结果
  1. if(result == 1) {
  2. System.out.println("Success");
  3. }
  • 受影响行数: 逻辑判断, 方法返回
  • 查询结果集: 迭代, 依次获取

3.6 释放资源

  • 遵循先开后关原则,释放所使用到的资源对象
  1. statement.close();
  2. conn.close();

3.7 综合案例

  • 整合以上核心六步, 实现在数据库表删除一条数据
  1. public class DeleteJDBC {
  2. public static void main(String[] args) throws Exception{
  3. //1. 加载驱动
  4. Class.forName("com.mysql.jdbc.Driver");
  5. //2. 获得连接对象
  6. Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/companydb", "root", "root");
  7. //3. 获得执行SQL的对象
  8. Statement statement = conn.createStatement();
  9. //4. 执行SQL语句, 并接收结果
  10. int result = statement.executeUpdate("delete from t_jobs where job_id = 'JAVA_Mgr'");
  11. //5. 处理结果
  12. if (result == 1) {
  13. System.out.println("删除成功!");
  14. }else{
  15. System.out.println("删除失败!");
  16. }
  17. //6. 释放资源
  18. statement.close();
  19. conn.close();
  20. }
  21. }

四. ResultSet(结果集)

  • 在执行查询SQL后,存放查询到的结果数据集

4.1 接收结果集

  • ResultSet rs = statement.executeQuery(sql);
  1. ResultSet rs = statement.executeQuery("select * from t_employees");

4.2 遍历ResultSet中的数据

  • ResultSet以表(table)结构进行临时结果的存储, 需要通过JDBC API将其中数据进行依次获取

    • 数据行指针: 初始位置在第一行数据前, 每调用一次boolean next()方法ResultSet的指针向下移动一行, 结果为true, 表示当前行有数据
    • rs.getXxx(整数);代表根据列的编号顺序获得, 从1开始
    • rs.getXxx("列名");代表根据列名获得
  1. boolean next() throws SQLException //判断 rs 的结果集中 下一行是否存在数据
4.2.1 遍历方法
  1. int getInt(int columnIndex) throws SQLException //获得当前行第N列的int值
  2. int getInt(String columnLabel) throws SQLException //获得当前行columnLabel列的int值
  3. double getDouble(int columnIndex) throws SQLException //获得当前行第N列的double值
  4. double getDouble(String columnLabel) throws SQLException //获得当前行columnLabel列的double值
  5. String getString(int columnIndex) throws SQLException //获得当前行第N列的String值
  6. String getString(String columnLabel) throws SQLException //获得当前行columnLabel列的String值
  • 注意: 列的编号从1开始

4.3 综合案例

4.3.1 根据列的名称获取
  1. public class QueryJdbc {
  2. public static void main(String[] args) throws Exception{
  3. //1. 注册驱动
  4. Class.forName("com.mysql.jdbc.Driver");
  5. //2. 获取连接对象
  6. Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/companydb", "root","root");
  7. //3. 获取执行SQL的对象
  8. Statement statement = conn.createStatement();
  9. //4. 执行SQL语句,接收结果
  10. ResultSet resultSet = statement.executeQuery("select * from t_jobs");
  11. //5. 处理结果
  12. while (resultSet.next()) {
  13. //对当前行每列数据进行获取, 根据列的编号
  14. String job_id = resultSet.getString("job_id");
  15. String job_title = resultSet.getString("job_title");
  16. String min_salary = resultSet.getString("min_salary");
  17. String max_salary = resultSet.getString("max_salary");
  18. System.out.println(job_id+"\t"+job_title+"\t"+min_salary+"\t"+max_salary);
  19. }
  20. //6. 释放资源
  21. resultSet.close();
  22. statement.close();
  23. conn.close();
  24. }
  25. }
4.3.2根据列的编号获取
  1. public class QueryJdbc2 {
  2. public static void main(String[] args) throws Exception{
  3. //1. 注册驱动
  4. Class.forName("com.mysql.jdbc.Driver");
  5. //2. 获取连接对象
  6. Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/companydb", "root","root");
  7. //3. 获取执行SQL的对象
  8. Statement statement = conn.createStatement();
  9. //4. 执行SQL语句,接收结果
  10. ResultSet resultSet = statement.executeQuery("select * from t_jobs");
  11. //5. 处理结果
  12. while (resultSet.next()) { //判断下一行是否有数据
  13. //对当前行每列数据进行获取, 根据列的编号
  14. String job_id = resultSet.getString(1);
  15. String job_title = resultSet.getString(2);
  16. String min_salary = resultSet.getString(3);
  17. String max_salary = resultSet.getString(3);
  18. System.out.println(job_id+"\t"+job_title+"\t"+min_salary+"\t"+max_salary);
  19. }
  20. //6. 释放资源
  21. resultSet.close();
  22. statement.close();
  23. conn.close();
  24. }
  25. }

五. 常见错误

  • java.lang.ClassNotFoundException:

    • 找不到类(类名书写错误, 没有导入jar包)
  • java.sql.SQLException:
    • 与sql语句相关的错误(约束错误, 表名列名书写错误) 建议: 在客户端工具中测试SQL语句之后再粘贴到代码中
  • com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column :
    • 列值String类型没有加单引号
  • Duplicate entry '1' for key 'PRIMARY' :
    • 主键值已存在或混乱, 更改主键值或清空表
  • com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'password' in:
    • 可能输入的值的类型不对, 确定在插入元素时, 其值所对应的类型是否正确

六. 综合案例[登陆]

6.1 创建表

  • 创建一张用户表user

    • id, 主键, 自动增长
    • 用户名, 字符串类型, 唯一, 非空
    • 密码, 字符串类型, 非空
    • 手机号码. 字符串类型
  • 插入;两条测试语句
  1. CREATE TABLE users(
  2. id INT PRIMARY KEY AUTO_INCREMENT,
  3. username VARCHAR(18) UNIQUE NOT NULL,
  4. `password` VARCHAR(18) NOT NULL,
  5. phone VARCHAR(11)
  6. )CHARSET=utf8;
  7. INSERT INTO users(username,`password`,phone) VALUES('zhangsan','123','12345678901');
  8. INSERT INTO users(username,`password`,phone) VALUES('lisi','321','12345678902');

6.2 实现登录

  • 用户通过控制台输入用户名和密码
  • 将用户输入的用户名和密码作为条件, 编写查询SQL语句
  • 如果该用户存在, 提示登录成功, 反之提示失败
  1. public class LoginJdbc {
  2. public static void main(String[] args) throws Exception{
  3. Scanner input = new Scanner(System.in);
  4. System.out.println("请输入用户名: ");
  5. String username = input.next();
  6. System.out.println("请输入密码: ");
  7. String password = input.next();
  8. Class.forName("com.mysql.jdbc.Driver");
  9. Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/companydb","root","root");
  10. Statement statement = conn.createStatement();
  11. ResultSet resultSet = statement.executeQuery("select username,password from users where username = '"+username+"' and password = '"+password+"'");
  12. if (resultSet.next()) { //查询到了数据
  13. System.out.println("登陆成功!");
  14. }else{
  15. System.out.println("登陆失败!");
  16. }
  17. resultSet.close();
  18. statement.close();
  19. conn.close();
  20. }
  21. }

七. SQL注入问题

7.1 什么是SQL注入

  • 用户输入的数据中有SQL关键字或语法并且参与了SQL语句的编译, 导致SQL语句编译后的条件含义为true, 一直得到正确的结果, 这种现象称为SQL注入

7.2 如何避免SQL注入

  • 由于编写的SQL语句是在用户输入数据, 整合后再进行编译, 所以为了避免SQL注入的问题, 我们要使SQL语句在用户输入数据前就已进行编译成完整的SQL语句, 再进行填充数据

八. PreparedStatement[重点]

  • PreparedStatement继承了Statement接口, 所以执行SQL语句的方法无异

8.1 PreparedStatement的应用

  • 作用:

    1. 预编译SQL语句, 效率高
    2. 安全, 避免SQL注入
    3. 可以动态的填充数据, 执行多个同构的SQL语句
8.1.1 参数标记
  1. //1. 预编译 SQL 语句
  2. PreparedStatement ps = conn.preparedStatement("select * from users where username=? and password=?");
  • 注意: JDBC中的所有参数都由?符号占位, 这被称为参数标记, 在执行SQL语句之前, 必须为每个参数提供值
8.1.2 动态参数绑定
  • ps.setXxx(下标,值) 参数下标从1开始, 为指定参数下标绑定值
  1. //2. 为参数下标赋值
  2. ps.setString(1,username);
  3. ps.setString(2,password);
  • 完整代码
  1. public class LoginJdbc2 {
  2. public static void main(String[] args) throws Exception{
  3. Scanner input = new Scanner(System.in);
  4. System.out.println("请输入用户名: ");
  5. String username = input.nextLine();
  6. System.out.println("请输入密码: ");
  7. String password = input.nextLine();
  8. Class.forName("com.mysql.jdbc.Driver");
  9. Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/companydb", "root", "root");
  10. //获得PreparedStatement对象,预编译SQL语句
  11. PreparedStatement ps = conn.prepareStatement("select * from users where username = ? and password = ?");
  12. //为?占位符赋值
  13. ps.setString(1,username);
  14. ps.setString(2,password);
  15. ResultSet resultSet = ps.executeQuery();
  16. if (resultSet.next()) {
  17. System.out.println("登陆成功!");
  18. }else{
  19. System.out.println("登陆失败");
  20. }
  21. resultSet.close();
  22. ps.close();
  23. conn.close();
  24. }
  25. }

九. 封装工具类

  • 在实际JDBC的使用中, 存在着大量的重复代码, 例如连接数据库, 关闭数据库等这些操作
  • 我们需要把传统的JDBC代码进行重构, 抽取出通用的JDBC工具类! 以后连接任何数据库, 释放资源都可以使用这个工具类

9.1 重用性方案

  • 封装获取连接, 释放资源两个方法

    • 提供public static Connection getConnection(){}方法
    • 提供public static void closeAll(Connection coon, Statement st, ResultSet rs){}方法
9.1.1 重用工具类实现
  1. public class JdbcUtils {
  2. static{//类加载,只执行一次
  3. try {
  4. Class.forName("com.mysql.jdbc.Driver");
  5. } catch (ClassNotFoundException e) {
  6. e.printStackTrace();
  7. }
  8. }
  9. //1. 获取连接
  10. public static Connection getConnection(){
  11. Connection conn = null;
  12. try {
  13. conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/companydb","root","root");
  14. } catch (SQLException throwables) {
  15. throwables.printStackTrace();
  16. }
  17. return conn;
  18. }
  19. //2. 释放资源
  20. public static void closeAll(Connection conn, Statement statement, ResultSet resultSet){
  21. try {
  22. if (resultSet != null){
  23. resultSet.close();
  24. }
  25. if (statement != null){
  26. statement.close();
  27. }
  28. if (conn != null){
  29. conn.close();
  30. }
  31. } catch (SQLException throwables) {
  32. throwables.printStackTrace();
  33. }
  34. }
  35. }

9.2 跨平台方案

  • 定义public static final Properties prop = new Properties();//读取配置文件的Map

  • 定义static{

    • //首次使用工具类时, 加载驱动

      InputStream is = JdbcUtils.class.getResourceAsStream("路径");//通过复用本类自带流, 读取jdbc.properties配置文件. classpath = bin

    • prop.load(is);//通过prop对象将流中的配置信息分割成键值对

    • String driverName = prop.getProperty("driver");//通过driverName的键获取对应的值(com.mysql.jdbc.Driver)

    • Class.forName(driverName);//加载驱动

  • }

9.2.1 跨平台工具类实现

(1) 在src目录下新建jdbc.properties配置文件

  1. driver=com.mysql.jdbc.Driver
  2. url=jdbc:mysql://localhost:3306/companydb?useUnicode=true&characterEncoding=utf8
  3. username=root
  4. password=root

(2) 工具类的封装

  1. public class JdbcUtils2 {
  2. private static final Properties PROPERTIES = new Properties();//存储配置文件的map
  3. static {
  4. InputStream is = JdbcUtils2.class.getResourceAsStream("/jdbc.properties");//通过复用本类自带流, 读取jdbc.properties配置文件
  5. try {
  6. PROPERTIES.load(is);//通过流,将配置文件内容加载到properties集合
  7. Class.forName(PROPERTIES.getProperty("driver"));//通过键"driver"得到值"com.mysql.jdbc.Driver"
  8. } catch (IOException e) {
  9. e.printStackTrace();
  10. } catch (ClassNotFoundException e) {
  11. e.printStackTrace();
  12. }
  13. }
  14. public static Connection getConnection() {
  15. Connection conn = null;
  16. try {
  17. conn = DriverManager.getConnection(PROPERTIES.getProperty("url"), PROPERTIES.getProperty("username"), PROPERTIES.getProperty("password"));//通过键"url"得到值"jdbc:mysql://localhost:3306/companydb",通过键"username"得到值"root",通过键"password"得到值"root"
  18. } catch (SQLException throwables) {
  19. throwables.printStackTrace();
  20. }
  21. return conn;
  22. }
  23. public static void closeAll(Connection conn, Statement statement, ResultSet resultSet) {
  24. try {
  25. if (resultSet != null) {
  26. resultSet.close();
  27. }
  28. if (statement != null) {
  29. statement.close();
  30. }
  31. if (conn != null) {//先开后关
  32. conn.close();
  33. }
  34. } catch (SQLException throwables) {
  35. throwables.printStackTrace();
  36. }
  37. }
  38. }

十. ORM 对象关系映射

  • ORM: (Object Relational Mapping)
  • 从数据库查询到的结果集(ResultSet)在进行遍历时, 逐行遍历, 取出的都是零散的数据, 在实际应用开发中, 我们需要将零散的数据进行封装整理

10.1 实体类(entity): 零散数据的载体

  • 一行数据中, 对多个零散的数据进行整理
  • 通过entity的规则对表中的数据进行对象的封装
  • 表名=类名; 列名=属性名; 提供各个属性的get,set方法
  • 提供无参构造方法(视情况添加有参构造)
10.1.1 ORM应用
  • entity实体类

    • 表名是t_jobs, 表有四列,分别是job_id, job_title, min_salary, max_salary所以我们创建一个T_Jobs类, 属性分别为四个列名
  1. public class T_Jobs {
  2. private String job_id;
  3. private String job_title;
  4. private String min_salary;
  5. private String max_salary;
  6. public T_Jobs() {
  7. }
  8. public String getJob_id() {
  9. return job_id;
  10. }
  11. public void setJob_id(String job_id) {
  12. this.job_id = job_id;
  13. }
  14. public String getJob_title() {
  15. return job_title;
  16. }
  17. public void setJob_title(String job_title) {
  18. this.job_title = job_title;
  19. }
  20. public String getMin_salary() {
  21. return min_salary;
  22. }
  23. public void setMin_salary(String min_salary) {
  24. this.min_salary = min_salary;
  25. }
  26. public String getMax_salary() {
  27. return max_salary;
  28. }
  29. public void setMax_salary(String max_salary) {
  30. this.max_salary = max_salary;
  31. }
  32. @Override
  33. public String toString() {
  34. return "T_Jobs{" +
  35. "job_id='" + job_id + '\'' +
  36. ", job_title='" + job_title + '\'' +
  37. ", min_salary='" + min_salary + '\'' +
  38. ", max_salary='" + max_salary + '\'' +
  39. '}';
  40. }
  41. }
  • 将查询到的数据进行封装, 将所有对象存入集合中, 方便后续使用
  1. public class TestORM {
  2. public static void main(String[] args) {
  3. Connection conn = null;
  4. PreparedStatement ps = null;
  5. ResultSet resultSet = null;
  6. List<T_Jobs> t_jobsList = new ArrayList<>();
  7. try {
  8. conn = JdbcUtils2.getConnection();
  9. ps = conn.prepareStatement("select * from t_jobs");
  10. resultSet = ps.executeQuery();
  11. while (resultSet.next()) {
  12. String job_id = resultSet.getString("job_id");
  13. String job_title = resultSet.getString("job_title");
  14. String min_salary = resultSet.getString("min_salary");
  15. String max_salary = resultSet.getString("max_salary");
  16. //创建对象, 封装查询到的零散数据
  17. T_Jobs t_jobs = new T_Jobs();
  18. t_jobs.setJob_id(job_id);
  19. t_jobs.setJob_title(job_title);
  20. t_jobs.setMin_salary(min_salary);
  21. t_jobs.setMax_salary(max_salary);
  22. //每遍历一次得到一个对象, 把对象存到集合里, 方便后续的使用
  23. t_jobsList.add(t_jobs);
  24. }
  25. //集合遍历
  26. for (T_Jobs t_jobs : t_jobsList) {
  27. System.out.println(t_jobs);
  28. }
  29. } catch (SQLException throwables) {
  30. throwables.printStackTrace();
  31. }finally {
  32. JdbcUtils2.closeAll(conn,ps,resultSet);
  33. }
  34. }
  35. }

十一. DAO 数据访问对象

  • DAO: (Data Access Object)
  • DAO实现了业务逻辑与数据库访问相分离
    • 对同一张表的所有操作封装在XxxDaoImpl对象中
    • 根据增删改查的不同功能实现具体的方法(insert, update, delete, select, selectAll)

11.1 创建数据库

  • 创建一张person表, 有以下列:

    • id: int, 主键 自动增长
    • name: varchar(20) 非空
    • age: int 非空
    • birthday: date
    • email: 字符串
    • address: 字符串
  1. CREATE TABLE person(
  2. id INT PRIMARY KEY AUTO_INCREMENT,
  3. `name` VARCHAR(20) NOT NULL,
  4. age INT NOT NULL,
  5. birthday DATE,
  6. email VARCHAR(20),
  7. address VARCHAR(20)
  8. )CHARSET=utf8;

11.2 封装实体类

  • 创建entity实体类Person,编写属性私有化, 构造方法, get/set 方法
  1. public class Person {//根据表名person, 创建Person类
  2. private int id;//根据表的列名编写类的各个属性(私有)
  3. private String name;
  4. private int age;
  5. private Date birthday;
  6. private String email;
  7. private String address;
  8. public Person() {
  9. }
  10. public Person(String name, int age, Date birthday, String email, String address) {
  11. this.name = name;
  12. this.age = age;
  13. this.birthday = birthday;
  14. this.email = email;
  15. this.address = address;
  16. }
  17. public Person(int id, String name, int age, Date birthday, String email, String address) {
  18. this.id = id;
  19. this.name = name;
  20. this.age = age;
  21. this.birthday = birthday;
  22. this.email = email;
  23. this.address = address;
  24. }
  25. public int getId() {
  26. return id;
  27. }
  28. public void setId(int id) {
  29. this.id = id;
  30. }
  31. public String getName() {
  32. return name;
  33. }
  34. public void setName(String name) {
  35. this.name = name;
  36. }
  37. public int getAge() {
  38. return age;
  39. }
  40. public void setAge(int age) {
  41. this.age = age;
  42. }
  43. public Date getBirthday() {
  44. return birthday;
  45. }
  46. public void setBirthday(Date birthday) {
  47. this.birthday = birthday;
  48. }
  49. public String getEmail() {
  50. return email;
  51. }
  52. public void setEmail(String email) {
  53. this.email = email;
  54. }
  55. public String getAddress() {
  56. return address;
  57. }
  58. public void setAddress(String address) {
  59. this.address = address;
  60. }
  61. @Override
  62. public String toString() {
  63. return "Person{" +
  64. "id=" + id +
  65. ", name='" + name + '\'' +
  66. ", age=" + age +
  67. ", birthday=" + birthday +
  68. ", email='" + email + '\'' +
  69. ", address='" + address + '\'' +
  70. '}';
  71. }
  72. }

11.3 编写DaoImpl类

  • 编写DaoImpl类, 提供增删改查方法. 使用JDBC开发步骤, 完成功能
  1. public class PersonDaoImpl {
  2. //1. 新增
  3. public int insert(Person person) {
  4. Connection conn = null;
  5. PreparedStatement ps = null;
  6. String sql = "insert into person(name,age,birthday,email,address) values(?,?,?,?,?)";//往person表里新增一条数据
  7. try {
  8. conn = DBUtils.getConnection();//调用跨平台工具类获取数据库连接对象
  9. ps = conn.prepareStatement(sql);//获取执行SQL语句的对象
  10. //为指定的参数下标赋值
  11. ps.setString(1,person.getName());
  12. ps.setInt(2,person.getAge());
  13. ps.setDate(3,null);
  14. ps.setString(4,person.getEmail());
  15. ps.setString(5,person.getAddress());
  16. int result = ps.executeUpdate();
  17. return result;//返回执行结果,result为1则成功,0则失败
  18. } catch (SQLException throwables) {
  19. throwables.printStackTrace();
  20. } finally {
  21. DBUtils.closeAll(conn,ps,null);//最后调用跨平台工具类释放资源
  22. }
  23. return 0;
  24. }
  25. //2. 修改
  26. public int update(Person person) {
  27. Connection conn = null;
  28. PreparedStatement ps = null;
  29. String sql = "update person set name=?,age=?,birthday=?,email=?,address=? where id = ?";
  30. try {
  31. conn = DBUtils.getConnection();
  32. ps = conn.prepareStatement(sql);
  33. ps.setString(1,person.getName());
  34. ps.setInt(2,person.getAge());
  35. ps.setDate(3,null);
  36. ps.setString(4,person.getEmail());
  37. ps.setString(5,person.getAddress());
  38. ps.setInt(6,person.getId());
  39. int result = ps.executeUpdate();
  40. return result;
  41. } catch (SQLException throwables) {
  42. throwables.printStackTrace();
  43. } finally {
  44. DBUtils.closeAll(conn,ps,null);
  45. }
  46. return 0;
  47. }
  48. //3. 删除
  49. public int delete(int id) {
  50. Connection conn = null;
  51. PreparedStatement ps = null;
  52. String sql = "delete from person where id = ?";
  53. try {
  54. conn = DBUtils.getConnection();
  55. ps = conn.prepareStatement(sql);
  56. ps.setInt(1,id);
  57. int result = ps.executeUpdate();
  58. return result;
  59. } catch (SQLException throwables) {
  60. throwables.printStackTrace();
  61. } finally {
  62. DBUtils.closeAll(conn,ps,null);
  63. }
  64. return 0;
  65. }
  66. //4. 查单条数据
  67. public Person select(int id) {
  68. Connection conn = null;
  69. PreparedStatement ps = null;
  70. ResultSet resultSet = null;
  71. String sql = "select * from person where id = ?";
  72. Person person = null;
  73. try {
  74. conn = DBUtils.getConnection();
  75. ps = conn.prepareStatement(sql);
  76. ps.setInt(1,id);
  77. resultSet = ps.executeQuery();
  78. if (resultSet.next()) {//如果查到数据
  79. person = new Person();//则创建一个对象
  80. int pid = resultSet.getInt("id");
  81. String name = resultSet.getString("name");
  82. int age = resultSet.getInt("age");
  83. Date birthday = resultSet.getDate("birthday");
  84. String email = resultSet.getString("email");
  85. String address = resultSet.getString("address");
  86. //通过set方法为属性赋值
  87. person.setId(pid);
  88. person.setName(name);
  89. person.setAge(age);
  90. person.setBirthday(birthday);
  91. person.setEmail(email);
  92. person.setAddress(address);
  93. }
  94. return person;
  95. } catch (SQLException throwables) {
  96. throwables.printStackTrace();
  97. } finally {
  98. DBUtils.closeAll(conn,ps,resultSet);
  99. }
  100. return null;
  101. }
  102. //5. 查所有数据
  103. public List<Person> selectAll() {
  104. Connection conn = null;
  105. PreparedStatement ps = null;
  106. ResultSet resultSet = null;
  107. String sql = "select * from person";
  108. Person person = null;
  109. List<Person> personList = new ArrayList<>();//创建一个集合,用来存放Person对象
  110. try {
  111. conn = DBUtils.getConnection();
  112. ps = conn.prepareStatement(sql);
  113. resultSet = ps.executeQuery();
  114. while (resultSet.next()) {
  115. int id = resultSet.getInt("id");
  116. String name = resultSet.getString("name");
  117. int age = resultSet.getInt("age");
  118. Date birthday = resultSet.getDate("birthday");
  119. String email = resultSet.getString("email");
  120. String address = resultSet.getString("address");
  121. person = new Person(id,name,age,birthday,email,address);//通过构造方法为属性赋值
  122. personList.add(person);
  123. }
  124. return personList;
  125. } catch (SQLException throwables) {
  126. throwables.printStackTrace();
  127. } finally {
  128. DBUtils.closeAll(conn,ps,resultSet);
  129. }
  130. return null;
  131. }
  132. }

十二. Date工具类

  • 现有问题: 数据库存储的数据类型为java.sql.Date. 而我们Java应用层存储日期类型为java.util.Date. 当我们用Java应用程序插入带有日期的数据到数据库中时, 需要进行转换

12.1 java.util.Date

  • Java语言常规应用层面的日期类型, 可以通过字符串创建对应的时间对象
  • 无法直接通过JDBC插入到数据库

12.2 java.sql.Date

  • 不可以通过字符串创建对应的时间对象, 只能通过毫秒值创建对象(1970年至今的毫秒值)
  • 可以直接通过JDBC插入到数据库

12.3 SimpleDateFormat

  • 格式化和解析日期的具体类. 允许进行格式化(日期-->文本), 解析(文本-->日期) 和规范化
12.3.1 SimpleDateFormat应用
  1. public class TestTimes {
  2. public static void main(String[] args) throws Exception{
  3. //格式化
  4. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
  5. //将字符串转日期 parse
  6. Date date = sdf.parse("2021-03-22");
  7. System.out.println(date);
  8. //将日期转字符串 format
  9. String str = sdf.format(date);
  10. System.out.println(str);
  11. //sql.Date 不支持字符串转换, 只支持毫秒值创建
  12. //通过util.Date拿到指定日期的毫秒值, 转换为sql.Date
  13. java.sql.Date sqlDate = new java.sql.Date(date.getTime());
  14. System.out.println(sqlDate);
  15. }
  16. }

12.4 封装DateUtils工具类

  1. public class DateUtils {
  2. private static final SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd");
  3. //1. 字符串转为util.Date
  4. public static java.util.Date strToUtil(String str) {
  5. try {
  6. return sdf.parse(str);
  7. } catch (ParseException e) {
  8. e.printStackTrace();
  9. }
  10. return null;
  11. }
  12. //2. util.Date转sql.Date
  13. public static java.sql.Date utilToSql(java.util.Date date) {
  14. return new java.sql.Date(date.getTime());
  15. }
  16. //3. util.Date转字符串
  17. public static String utilToString(java.util.Date date) {
  18. return sdf.format(date);
  19. }
  20. }

十三. Service业务逻辑

13.1 什么是业务?

(软件所提供的一个功能就叫业务)

service层核心思想

站在用户角度, 一个功能即是一个业务,可能需要多个DAO组成

  • 转账(业务): A账户存款, B账户取款

    • Service业务逻辑层业务功能对应Service中一个方法

AccountServiceImpl{

transfer(){

saveMoney();

takeMoney();

}

}

AccountDaoImpl{

saveMoney();

takeMoney();

}

  • 查看电商所有商品(业务): 销量最高的, 优惠打折的, 最新上架的

ProductServiceImpl{

showProduct(){

hostProduct();

salesProduct();

newProduct();

}

}

ProductDaoImpl{

hostProduct();

salesProduct();

newProduct();

}

13.2 Service开发流程

client

int result = AccountServiceImpl.transfer();

if (result > 0) {

//成功

}else {

//失败

}

AccountServiceImpl {

public int transfer(){

//1.验证卡号密码

//2.验证金额是否充足

//3.验证对方卡号

//4.A账户扣钱

//5.B账户加钱

return 0/1;

}

}

AccountDaoImpl{

//1.验证卡号密码

//2.验证金额是否充足

//3.验证对方卡号

//4.A账户扣钱

//5.B账户加钱

}

13.2.1 编写service实现转账功能
  1. /**
  2. * @description: 转账业务
  3. * @param: fromNo 转账卡号
  4. * @param: pwd 转账卡的密码
  5. * @param: toNo 收钱卡号
  6. * @param: money 转账金额
  7. */
  8. public class AccountsServiceImpl {
  9. public String transfer(String fromNo,String pwd,String toNo,double money) {//1. 收参
  10. String result = "转账失败!"
  11. //2. 组织完善业务功能
  12. AccountsDaoImpl accountsDao = new AccountsDaoImpl();
  13. try {
  14. //2.1 验证fromNo是否存在
  15. Accounts account = accountsDao.select(fromNo);
  16. if (account == null) {
  17. throw new RuntimeException("您的卡号不存在!");
  18. }
  19. //2.2 验证fromNo的密码是否正确
  20. if (!account.getPassword().equals(pwd)) {
  21. throw new RuntimeException("您的密码错误!");
  22. }
  23. //2.3 验证fromNo的余额是否充足
  24. if (account.getBalance() < money) {
  25. throw new RuntimeException("您的余额不足!");
  26. }
  27. //2.4 验证toNo的卡号是否存在
  28. Accounts toAccount = accountsDao.select(toNo);
  29. if (toAccount == null) {
  30. throw new RuntimeException("抱歉,对方卡号不存在!");
  31. }
  32. //2.5 减少fromNo的余额
  33. //修改自己的金额,将余额减去转账金额 替换原有的属性
  34. account.setBalance(account.getBalance() - money);
  35. accountsDao.update(account);
  36. //2.6 增加toNo的余额
  37. toAccount.setBalance(toAccount.getBalance() + money);
  38. accountsDao.update(toAccount);
  39. result = "转账成功!";
  40. } catch (Exception e) {
  41. e.printStackTrace();
  42. } finally {
  43. DBUtils.closeAll(conn,null,null);
  44. }
  45. return result;
  46. }
  47. }

十四. 事务

  • 在JDBC中, 获得Connection对象开始事务---提交或回滚---关闭连接. 其事务策略是

    • conn.setAutoCommit(false);//true等价于1, false等价于0
    • conn.commit();//手动提交事务
    • conn.rollback();//手动回滚事务

14.1 service层控制事务

  1. public class AccountsServiceImpl {
  2. public String transfer(String fromNo,String pwd,String toNo,double money) {//1. 收参
  3. String result = "转账失败!";
  4. //2. 组织完善业务功能
  5. AccountsDaoImpl accountsDao = new AccountsDaoImpl();
  6. //拿一个连接
  7. Connection conn = null;
  8. try {
  9. //建立了一个数据库连接
  10. conn = DBUtils.getConnection();
  11. System.out.println("service: "+conn);
  12. //开启事务,并关闭事务的自动提交
  13. conn.setAutoCommit(false);
  14. //2.1 验证fromNo是否存在
  15. Accounts account = accountsDao.select(fromNo);
  16. if (account == null) {
  17. throw new RuntimeException("您的卡号不存在!");
  18. }
  19. //2.2 验证fromNo的密码是否正确
  20. if (!account.getPassword().equals(pwd)) {
  21. throw new RuntimeException("您的密码错误!");
  22. }
  23. //2.3 验证fromNo的余额是否充足
  24. if (account.getBalance() < money) {
  25. throw new RuntimeException("您的余额不足!");
  26. }
  27. //2.4 验证toNo的卡号是否存在
  28. Accounts toAccount = accountsDao.select(toNo);
  29. if (toAccount == null) {
  30. throw new RuntimeException("抱歉,对方卡号不存在!");
  31. }
  32. //2.5 减少fromNo的余额
  33. //修改自己的金额,将余额减去转账金额 替换原有的属性
  34. account.setBalance(account.getBalance() - money);
  35. accountsDao.update(account);
  36. //2.6 增加toNo的余额
  37. toAccount.setBalance(toAccount.getBalance() + money);
  38. accountsDao.update(toAccount);
  39. result = "转账成功!";
  40. //执行到这里,没有异常,则提交事务
  41. conn.commit();
  42. } catch (RuntimeException | SQLException e) {
  43. e.printStackTrace();
  44. //转账失败,则整个事务回滚
  45. try {
  46. //出现异常,回滚
  47. System.out.println("出现了异常,回滚整个事务!");
  48. conn.rollback();
  49. } catch (SQLException throwables) {
  50. throwables.printStackTrace();
  51. }
  52. } finally {
  53. DBUtils.closeAll(conn,null,null);
  54. }
  55. return result;
  56. }
  57. }
  • 问题: 当转账程序出现异常,事务控制成功了吗?

14.2 解决方案1: 传递Connection

  • 为解决线程中Connection对象不同步的问题,可以将Connection对象通过service传递给各个DAO方法吗?
14.2.1 传递的问题
  • 如果使用传递Connection, 容易造成接口污染(BadSmell)
  • 定义接口是为了更容易更换实现, 而将Connection定义在接口中, 会造成污染当前接口

14.3 解决方案2: ThreadLocal

  • 可以将整个线程中(单线程), 存储一个共享值
  • 线程拥有一个类似Map的属性, 键值对结构<ThreadLocal对象, 值>

14.4 ThreadLocal应用

  • 一个线程共享同一个ThreadLocal, 在整个流程中任一环节可以存值或取值
14.4.1 参数绑定
  • 在DBUtils中, 将当前Connection对象添加到ThreadLocal中
  1. public class DBUtils {
  2. private static final Properties PROPERTIES = new Properties();
  3. private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
  4. static {
  5. InputStream is = DBUtils.class.getResourceAsStream("/jdbc.properties");
  6. try {
  7. PROPERTIES.load(is);
  8. Class.forName(PROPERTIES.getProperty("driver"));
  9. } catch (IOException e) {
  10. e.printStackTrace();
  11. } catch (ClassNotFoundException e) {
  12. e.printStackTrace();
  13. }
  14. }
  15. public static Connection getConnection() {
  16. Connection conn = threadLocal.get();//获取当前线程中存储的Connection对象,赋值给conn
  17. try {
  18. if (conn == null) {
  19. conn = DriverManager.getConnection(PROPERTIES.getProperty("url"), PROPERTIES.getProperty("username"), PROPERTIES.getProperty("password"));
  20. threadLocal.set(conn);//把连接存储到当前线程共享中
  21. }
  22. } catch (SQLException throwables) {
  23. throwables.printStackTrace();
  24. }
  25. return conn;
  26. }
  27. //关闭所有连接 增加 threadLocal.remove(); 移除
  28. public static void closeAll(Connection conn, Statement statement, ResultSet resultSet) {
  29. try {
  30. if (resultSet != null) {
  31. resultSet.close();
  32. }
  33. if (statement != null) {
  34. statement.close();
  35. }
  36. if (conn != null) {
  37. conn.close();
  38. threadLocal.remove();//将conn移除
  39. }
  40. } catch (SQLException throwables) {
  41. throwables.printStackTrace();
  42. }
  43. }
  44. }

十五. 事务的封装

  • 将事务的开启, 提交, 回滚都封装在工具类中, 业务层调用即可

15.1 完善工具类

  1. //开启事务
  2. public static void begin() {
  3. try {
  4. Connection conn = getConnection();
  5. conn.setAutoCommit(false);//开启事务,关闭自动提交
  6. } catch (SQLException throwables) {
  7. throwables.printStackTrace();
  8. }
  9. }
  10. //提交事务
  11. public static void commit() {
  12. Connection conn = null;
  13. try {
  14. conn = getConnection();
  15. conn.commit();
  16. } catch (SQLException throwables) {
  17. throwables.printStackTrace();
  18. } finally {
  19. closeAll(conn,null,null);
  20. }
  21. }
  22. //回滚事务
  23. public static void rollback() {
  24. Connection conn = null;
  25. try {
  26. conn = getConnection();
  27. conn.rollback();
  28. } catch (SQLException throwables) {
  29. throwables.printStackTrace();
  30. } finally {
  31. closeAll(conn,null,null);
  32. }
  33. }

十六. 三层架构

16.1 什么是三层

  • 表示层(UI, Main)

    • 命名: XXXView
    • 职责:
      1. 收集用户输入数据
      2. 调用业务逻辑层, 完成业务方法
      3. 展示数据或展示操作结果
  • 业务逻辑层(service)
    • 命名: XXXServiceImpl
    • 职责:
      1. 开启事务
      2. 调用DAO层
      3. 处理数据
      4. 提交或回滚
  • 数据访问层(DAO)
    • 命名: XXXDaoImpl
    • 职责:
      1. 查询相关业务逻辑的数据
      2. 根据相关业务逻辑修改的数据

16.2 三层架构项目搭建(按开发步骤)

  • utils 存放工具类 (DBUtils)
  • entity 存放实体类 (Person)
  • dao 存放 DAO 接口 (PersonDao)
    • impl存放 DAO 接口实现类 (PersonDaoImpl)
  • service 存放 service 接口 (PersonServiceImpl)
    • impl存放 service 接口实现类 (PersonServiceImpl)
  • view 存放程序启动类 (main)
  • 程序设计时, 考虑易修改, 易扩展, 为service层和DAO层设计接口, 便于未来更换实现类
  1. //1. 更自然的使用多态(父类接口引用指向子类对象)
  2. //2. 更容易更换具体实现
  3. public interface AccountsDao {
  4. int insert(Accounts accounts);
  5. int delete(String cardNo);
  6. int update(Accounts accounts);
  7. Accounts select(String cardNo);
  8. List<Accounts> selectAll();
  9. }
  10. public interface AccountsService {
  11. String transfer(String fromNo,String pwd,String toNo,double money);
  12. }

十七. DaoUtils

  • 在DAO层中, 对数据库表的增, 删, 改, 查操作存在代码冗余, 可对其进行抽取封装DaoUtils工具类实现复用

17.1 commonUpdate

  1. /*
  2. * 公共处理增, 删, 改的方法
  3. *
  4. * @param sql 执行的sql语句
  5. * @param args 参数列表,为占位符赋值
  6. * @return 受影响的行数
  7. */
  8. public class DaoUtils {
  9. public int commonUpdate(String sql,Object... args) {
  10. Connection conn = null;
  11. PreparedStatement ps = null;
  12. conn = DbUtils.getConnection();
  13. try {
  14. ps = conn.prepareStatement(sql);
  15. for (int i = 0; i < args.length; i++) {
  16. ps.setObject(i+1,args[i]);
  17. }
  18. return ps.executeUpdate();
  19. } catch (SQLException throwables) {
  20. throwables.printStackTrace();
  21. } finally {
  22. DbUtils.closeAll(null,ps,null);
  23. }
  24. return 0;
  25. }
  26. }

17.2 commonselect

  1. /*
  2. * 公共查询方法 (可查询单个对象, 也可以查询多个对象,可以查任何一张表)
  3. *
  4. * @param sql
  5. * @param args
  6. * @return 集合
  7. */
  8. // select * from t_account;
  9. // select * from t_student;
  10. // select * from person;
  11. // 工具不知道查的是什么 调用者知道
  12. // 封装对象,对象赋值 调用者清除
  13. public List<T> commonSelect(String sql, RowMapper<T> rowMapper, Object... args) {
  14. Connection conn = null;
  15. PreparedStatement ps = null;
  16. ResultSet resultSet = null;
  17. List<T> list = new ArrayList<>();
  18. conn = DbUtils.getConnection();
  19. try {
  20. ps = conn.prepareStatement(sql);
  21. if (args != null) {
  22. for (int i = 0; i < args.length; i++) {
  23. ps.setObject(i+1,args[i]);//为占位符赋值
  24. }
  25. }
  26. resultSet = ps.executeQuery();
  27. while (resultSet.next()) {
  28. // id.name,age,birthday,email,address
  29. // 如何根据查询结果完成ORM,如何进行对象的创建及赋值
  30. T t = rowMapper.getRow(resultSet);//回调--->调用者提供一个封装方法ORM
  31. list.add(t);
  32. }
  33. return list;
  34. } catch (SQLException throwables) {
  35. throwables.printStackTrace();
  36. }
  37. return null;
  38. }

RowMapper接口

  1. public interface RowMapper<T> {
  2. T getRow(ResultSet resultSet);
  3. }

PersonRowMapper实现类

  1. public class PersonRowMapper implements RowMapper<Person> {
  2. @Override
  3. public Person getRow(ResultSet resultSet) {
  4. Person person = null;
  5. try {
  6. int pid = resultSet.getInt("id");
  7. String name = resultSet.getString("name");
  8. int age = resultSet.getInt("age");
  9. Date birthday = resultSet.getDate("birthday");
  10. String email = resultSet.getString("email");
  11. String address = resultSet.getString("address");
  12. person = new Person(pid,name,age,birthday,email,address);
  13. return person;
  14. } catch (SQLException throwables) {
  15. throwables.printStackTrace();
  16. }
  17. return null;
  18. }
  19. }

十八. Druid连接池

  • 在程序初始化时, 预先创建指定数量的数据库连接对象存储在池中, 当需要连接数据库时, 从连接池中取出现有连接, 使用完毕后, 也不会进行关闭, 而是放回池中, 实现复用, 节省资源

18.1 Druid连接池使用步骤

  • 创建 database properties配置文件
  • 引入 druid.1.1.5.jar文件
18.1.1 database.properties配置文件
  1. #<!-- 连接设置 -->
  2. driverClassName=com.mysql.jdbc.Driver
  3. url=jdbc:mysql://localhost:3306/companydb?useUnicode=true&characterEncoding=utf8
  4. username=root
  5. password=root
  6. #<!-- 初始化连接 -->
  7. initialSize=10
  8. #<!-- 最大连接数量 -->
  9. maxActive=30
  10. #<!-- 最小空闲连接 -->
  11. minIdle=5
  12. #<!-- 超时等待时间以毫秒为单位 60000毫秒/1000等于60秒 -->
  13. maxWait=5000
18.1.2 连接池工具类
  1. public class DbUtils {
  2. //声明连接池对象
  3. private static DruidDataSource ds;
  4. static {
  5. Properties properties = new Properties();
  6. InputStream is = DbUtils.class.getResourceAsStream("/database.properties");
  7. try {
  8. properties.load(is);
  9. //创建连接池
  10. ds = (DruidDataSource)DruidDataSourceFactory.createDataSource(properties);
  11. } catch (IOException e) {
  12. e.printStackTrace();
  13. } catch (Exception e) {
  14. e.printStackTrace();
  15. }
  16. }
  17. public static Connection getConnection() {
  18. try {
  19. return ds.getConnection();
  20. } catch (SQLException throwables) {
  21. throwables.printStackTrace();
  22. }
  23. return null;
  24. }
  25. }

十九. Apache的DbUtils的使用

  • Commons DbUtils 是Apache组织提供的一个对JDBC进行简单封装的开源工具类库, 使用它能够简化JDBC应用程序的开发! 同时, 不会影响程序的性能

19.1 DbUtils简介

  • DbUtils是java编程中数据库操作实用小工具, 小巧, 简单, 实用

    • 对于数据库表的查询操作, 可以把结果转换为List, Array, Set等集合, 便于操作
    • 对于数据库表的DML操作, 也变得很简单(只需要写SQL语句)
19.1.1 DbUtils主要包含
  • ResultSetHandler接口: 转换类型接口

    • BeanHandler类: 实现类, 把一条记录转换成对象
    • BeanListHandler类: 实现类, 把多条数据转换成List集合
    • ScalarHandler类: 实现类, 适合获取一行一列的数据
  • QueryRunner: 执行sql语句的类
    • 增, 删, 改: update();
    • 查询: query();

19.2 DbUtils的使用步骤

  • 导入jar 包

    • mysql连接驱动jar包: mysql-connector-java-5.1.25-bin.jar
    • Druid连接池jar包: druid-1.1.5.jar
    • database.properties配置文件
    • DbUtils工具jar包: commons-dbutils-1.7.jar
19.2.1 DbUtils工具类
  1. public class DbUtils {
  2. //声明连接池对象
  3. private static DruidDataSource ds;
  4. static {
  5. //实例化配置对象
  6. Properties properties = new Properties();
  7. InputStream is = DbUtils.class.getResourceAsStream("/database.properties");
  8. try {
  9. //加载配置文件内容
  10. properties.load(is);
  11. //创建连接池
  12. ds = (DruidDataSource)DruidDataSourceFactory.createDataSource(properties);
  13. } catch (IOException e) {
  14. e.printStackTrace();
  15. } catch (Exception e) {
  16. e.printStackTrace();
  17. }
  18. }
  19. //获取连接对象
  20. public static Connection getConnection() {
  21. try {
  22. return ds.getConnection();
  23. } catch (SQLException throwables) {
  24. throwables.printStackTrace();
  25. }
  26. return null;
  27. }
  28. //返回一个数据源ds
  29. public static DataSource getDataSource() {
  30. return ds;
  31. }
  32. //释放资源
  33. //调用close()方法,实际调用的是DruidPooledConnection实现类里的close()
  34. }
19.2.2 UserDaoImpl数据访问对象
  1. public class UserDaoImpl implements UserDao {
  2. //创建QueryRunner对象,并传递一个数据源对象
  3. private QueryRunner queryRunner = new QueryRunner(DbUtils.getDataSource());
  4. @Override
  5. //1. 新增
  6. public int insert(User user) {
  7. Object[] params = {user.getUserId(),user.getUsername(),user.getPassword(),user.getAddress(),user.getPhone()};
  8. try {
  9. int result = queryRunner.update("insert into user(userId,username,password,address,phone) values(?,?,?,?,?)", params);
  10. return result;
  11. } catch (SQLException throwables) {
  12. throwables.printStackTrace();
  13. }
  14. return 0;
  15. }
  16. @Override
  17. //2. 删除
  18. public int delete(int userId) {
  19. try {
  20. int result = queryRunner.update("delete from user where userId=?", userId);
  21. return result;
  22. } catch (SQLException throwables) {
  23. throwables.printStackTrace();
  24. }
  25. return 0;
  26. }
  27. @Override
  28. //3. 修改
  29. public int update(User user) {
  30. Object[] params = {user.getUsername(),user.getPassword(),user.getAddress(),user.getPhone(),user.getUserId()};
  31. try {
  32. int result = queryRunner.update("update user set username=?,password=?,address=?,phone=? where userId=?", params);
  33. return result;
  34. } catch (SQLException throwables) {
  35. throwables.printStackTrace();
  36. }
  37. return 0;
  38. }
  39. @Override
  40. //4. 查单个
  41. public User select(int userId) {
  42. try {
  43. //把查询到的记录封装成 指定对象
  44. User user = queryRunner.query("select * from user where userId=?", new BeanHandler<User>(User.class), userId);
  45. return user;
  46. } catch (SQLException throwables) {
  47. throwables.printStackTrace();
  48. }
  49. return null;
  50. }
  51. @Override
  52. //5. 查所有
  53. public List<User> selectAll() {
  54. try {
  55. List<User> userList = queryRunner.query("select * from user", new BeanListHandler<User>(User.class));
  56. return userList;
  57. } catch (SQLException throwables) {
  58. throwables.printStackTrace();
  59. }
  60. return null;
  61. }
  62. @Override
  63. //6. 查数量(单行单列)
  64. public long selectUserNums() {
  65. try {
  66. long count = queryRunner.query("select count(*) from user", new ScalarHandler<>());
  67. return count;
  68. } catch (SQLException throwables) {
  69. throwables.printStackTrace();
  70. }
  71. return 0;
  72. }
  73. }

2_JDBC的更多相关文章

随机推荐

  1. 使用Java客户端发送消息和消费的应用

    体验链接:https://developer.aliyun.com/adc/scenario/fb1b72ee956a4068a95228066c3a40d6 实验简介 本教程将Demo演示使用jav ...

  2. Linux 任务计划管理

    在某个时间点执行一次任务 at工具 作用:用于执行一次性任务,需要指定执行的时间. at工具来源于at软件包. 依赖与atd服务,需要启动才能实现at任务.#通过这个守护进程见监控at的相关内容 #选 ...

  3. 字节输出流的续写和换行和字节输入流InputStream类&FileInputStream类介绍

    数据追加续写 每次程序运行,创建输出流对象,都会清空目标文件中的数据.如何保目标文件中的数据,还能继续添加新数据呢? public FileOutputStream(File file,boolean ...

  4. 从零开始Blazor Server(4)--登录系统

    说明 上一篇文章中我们添加了Cookie授权,可以跳转到登录页了.但是并没有完成登录,今天我们来完成它. 我们添加Cookie授权的时候也说了,这套跟MVC一模一样,所以我们登录也是跟MVC一模一样. ...

  5. Python算法之动态规划(Dynamic Programming)解析:二维矩阵中的醉汉(魔改版leetcode出界的路径数)

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_168 现在很多互联网企业学聪明了,知道应聘者有目的性的刷Leetcode原题,用来应付算法题面试,所以开始对这些题进行" ...

  6. Hive存储格式之RCFile详解,RCFile的过去现在和未来

    我在整理Hive的存储格式和压缩格式,本来打算一篇发出来,结果其中一小节就有很多内容,于是打算写成Hive存储格式和压缩格式系列. 本节主要讲一下Hive存储格式最早的典型的列式存储格式RCFile. ...

  7. 如何保证遍历parent的时候的task的存在性

    在一次crash的排查过程中,有这么一个内核模块,他需要往上遍历父进程, 但是在拿父进程task_struct中的一个成员的时候,发现为NULL了, 具体查看父进程,原来它收到信号退出中. 那么怎么保 ...

  8. Python入门系列(一)安装环境

    python是什么 python是一门很受欢迎的语言,除了不能生孩子以外,其它都可以做. 它擅长的领域是脚本工具和科学数据这一块,比如大数据,数据分析什么的. python安装 为了演示和验证教程可用 ...

  9. dotnet 设计规范 · 抽象类

    X 不要定义 public 或 protected internal 访问的构造函数.默认 C# 语言不提供抽象类的公开构造函数方法. 如果一个构造函数定义为公开,只有在开发者需要创建这个类的实例的时 ...

  10. Codeforces Round #604 (Div. 2) -D

    Problem - D - Codeforces 题意 : 有 a 个0,b个1,c个2,d个3,构成一个序列,使得每两个数字之间的差值为1 题解: 就是以四种数字分别为起点,暴力模拟 #includ ...