连接池、JDBCTemplate

学习目标

  1. 能够说出什么是数据库元数据
  2. 掌握自定义数据库框架,实现增加、删除、更新方法
  3. 掌握JdbcTemplate实现增删改
  4. 掌握JdbcTemplate实现增查询
  5. 能够理解分层的作用
  6. 掌握使用三层架构实现用户注册案例

第1章 数据库元数据

1.1 元数据的基本概述

元数据:数据库、表、列的定义信息。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EUvpHPiJ-1582252345094)(imgs\元数据01.png)]

1.2 ParameterMetaData

ParameterMetaData可用于获取有关PreparedStatement对象中每个参数标记的类型和属性。

select * from user where name=? and password=?
// ParameterMetaData可以用来获取?的个数和类型

1.2.1 如何获取ParameterMetaData

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-az3AMqgX-1582252345095)(imgs\元数据02.png)]
通过PreparedStatementgetParameterMetaData()方法来获取到ParameterMetaData对象

1.2.2 API介绍

  1. int getParameterCount() 获取PreparedStatement的SQL语句参数?的个数
    
  2. int getParameterType(int param) 获取指定参数的SQL类型。  
    

1.2.3 使用步骤

  1. 获取ParameterMetaData对象
  2. 使用对象调用方法

1.2.4 注意事项

  1. 不是所有的数据库驱动都能后去到参数类型(MySQL会出异常)

1.2.5 案例代码

public class Demo01 {
	public static void main(String[] args) throws Exception {
		Connection conn = DataSourceUtils.getConnection();
		String sql = "INSERT INTO  student (name, age, score) VALUES (?, ?, ?)";
		PreparedStatement stmt = conn.prepareStatement(sql);
		ParameterMetaData md = stmt.getParameterMetaData();
		System.out.println("参数个数: " + md.getParameterCount());

		// Parameter metadata not available for the given statement
		// MySQL不支持获取参数类型
		// System.out.println("参数类型: " + md.getParameterType(1));
	}
}

1.3 ResultSetMetaData

ResultSetMetaData可用于获取有关ResultSet对象中列的类型和属性的信息。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TMZwZiXX-1582252345096)(imgs\元数据03.png)]

1.3.1 如何获取ResultSetMetaData

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oKxoeHI3-1582252345096)(imgs\元数据04.png)]
通过ResultSetgetMetaData()方法来获取到ResultSetMetaData对象

1.3.2 API介绍

  1. int getColumnCount() 返回此 ResultSet对象中的列数
    
  2. String getColumnName(int column) 获取指定列的名称
    
  3. String getColumnTypeName(int column) 获取指定列的数据库特定类型名称
    

1.3.3 使用步骤

  1. 获取ResultSetMetaData对象
  2. 使用对象调用方法

1.3.4 案例代码

// ResultSetMetaData
public static void test02() throws SQLException {
    Connection conn = DataSourceUtils.getConnection();
    String sql = "SELECT * FROM student WHERE id=1";
    PreparedStatement stmt = conn.prepareStatement(sql);
    ResultSet rs = stmt.executeQuery();
    // 获取结果集元数据
    ResultSetMetaData md = rs.getMetaData();
    int num = md.getColumnCount();
    System.out.println("列数:" + num);
    for (int i = 0; i < num; i++) {
        System.out.println("列名:" + md.getColumnName(i + 1)); // 获取列名
        System.out.println("列类型:" + md.getColumnTypeName(i + 1)); // 获取类的类型
        System.out.println("-----------");
    }
}

1.3.5 案例效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jc4uT5ZE-1582252345097)(imgs\元数据05.png)]

1.4 案例自定义数据库框架,实现增加、删除、更新方法

目前使用连接池工具类操作数据库的代码

// 增加数据
public static void testInsert() throws SQLException {
    // 获取连接
    Connection conn = DataSourceUtils.getConnection();

    String sql = "INSERT INTO student (name, age, score) VALUES (?, ?, ?);";
    PreparedStatement pstmt = conn.prepareStatement(sql);

    // 设置参数
    pstmt.setString(1, "刘德华");
    pstmt.setInt(2, 57);
    pstmt.setInt(3, 99);
    int i = pstmt.executeUpdate();
    System.out.println("影响的行数:" + i);

    // 关闭连接
    DataSourceUtils.close(conn, pstmt);
}

// 修改数据
public static void testUpdate() throws SQLException {
    Connection conn = DataSourceUtils.getConnection();

    String sql = "UPDATE student SET name=? WHERE id=?;";
    PreparedStatement pstmt = conn.prepareStatement(sql);
    pstmt.setString(1, "张学友");
    pstmt.setInt(2, 2);
    int i = pstmt.executeUpdate();
    System.out.println("影响的行数:" + i);

    DataSourceUtils.close(conn, pstmt);
}

// 删除数据
public static void testDelete() throws SQLException {
    Connection conn = DataSourceUtils.getConnection();

    String sql = "DELETE FROM student WHERE id=?;";
    PreparedStatement pstmt = conn.prepareStatement(sql);
    pstmt.setInt(1, 3);
    int i = pstmt.executeUpdate();
    System.out.println("影响的行数:" + i);

    DataSourceUtils.close(conn, pstmt);
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gjbG9RTP-1582252345097)(imgs\元数据06.png)]
存在的问题:我们发现,增删改都需要获取连接,关闭连接,只是SQL语句不同。我们可以使用元数据来自动给SQL设置参数,合并成一个方法。

DataSourceUtils中增加一个方法update

/*
    String sql: sql语句
    Object[] params: 参数数组
 */
public static int update(String sql, Object[] params) {
    Connection conn = null;
    PreparedStatement st = null;

    try {
        conn = getConnection();
        st = conn.prepareStatement(sql);
        // 获取到参数个数
        ParameterMetaData md = st.getParameterMetaData();
        int num = md.getParameterCount(); // 参数的个数
        for (int i = 0; i < num; i++) {
            // 将参数赋值给对应的?号
            st.setObject(i + 1, params[i]);
        }
        return st.executeUpdate();

    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        close(conn, st);
    }
    return 0;
}

增删改都调用update方法,只需要编写SQL语句和设置参数即可,可以减少代码。

// 增加数据
public static void testInsert2() throws SQLException {
    String sql = "INSERT INTO student (name, age, score) VALUES (?, ?, ?);";
    Object[] params = {"郭富城", 55, 88};
    int i = DataSourceUtils.update(sql, params);
    System.out.println("影响的行数:" + i);
}

// 修改数据
public static void testUpdate2() throws SQLException {
    String sql = "UPDATE student SET name=? WHERE id=?;";
    Object[] params = {"黎明", 1};
    int i = DataSourceUtils.update(sql, params);
    System.out.println("影响的行数:" + i);
}

// 删除数据
public static void testDelete2() throws SQLException {
    String sql = "DELETE FROM student WHERE id=?;";
    Object[] params = {7};
    int i = DataSourceUtils.update(sql, params);
    System.out.println("影响的行数:" + i);
}

第2章 JdbcTemplate

2.1 JdbcTemplate概念

​ JDBC已经能够满足大部分用户最基本的需求,但是在使用JDBC时,必须自己来管理数据库资源如:获取PreparedStatement,设置SQL语句参数,关闭连接等步骤。JdbcTemplate就是Spring对JDBC的封装,目的是使JDBC更加易于使用。JdbcTemplate是Spring的一部分。
​ JdbcTemplate处理了资源的建立和释放。他帮助我们避免一些常见的错误,比如忘了总要关闭连接。他运行核心的JDBC工作流,如Statement的建立和执行,而我们只需要提供SQL语句和提取结果。
Spring源码地址:https://github.com/spring-projects/spring-framework
在JdbcTemplate中执行SQL语句的方法大致分为3类:

  1. execute:可以执行所有SQL语句,一般用于执行DDL语句。
  2. update:用于执行INSERTUPDATEDELETE等DML语句。
  3. queryXxx:用于DQL数据查询语句。

2.2 JdbcTemplate使用过程

2.2.1 Druid基于配置文件实现连接池

2.2.1.1 API介绍

org.springframework.jdbc.core.JdbcTemplate类方便执行SQL语句

  1. public JdbcTemplate(DataSource dataSource)
    创建JdbcTemplate对象,方便执行SQL语句
    
  2. public void execute(final String sql)
    execute可以执行所有SQL语句,因为没有返回值,一般用于执行DDL语句。
    
2.2.1.2 使用步骤
  1. 准备DruidDataSource连接池
  2. 导入依赖的jar包
    • spring-beans-4.1.2.RELEASE.jar
    • spring-core-4.1.2.RELEASE.jar
    • spring-jdbc-4.1.2.RELEASE.jar
    • spring-tx-4.1.2.RELEASE.jar
    • com.springsource.org.apache.commons.logging-1.1.1.jar
      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xBJXuK6V-1582252345098)(imgs\连接池12.png)]
  3. 创建JdbcTemplate对象,传入Druid连接池
  4. 调用executeupdatequeryXxx等方法
2.2.1.3 案例代码
public class Demo04 {
	public static void main(String[] args) {
		// 创建表的SQL语句
		String sql = "CREATE TABLE product("
				+ "pid INT PRIMARY KEY AUTO_INCREMENT,"
				+ "pname VARCHAR(20),"
				+ "price DOUBLE"
				+ ");";
				
		JdbcTemplate jdbcTemplate = new JdbcTemplate(JdbcUtils.getDataSource());
		jdbcTemplate.execute(sql);
	}
}
2.2.1.4 案例效果
  1. 代码效果
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KFtYtobN-1582252345098)(imgs\连接池13.png)]
  2. 执行SQL后创建数据库效果
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ygDWIU2Z-1582252345099)(imgs\连接池14.png)]

2.3 JdbcTemplate实现增删改

2.3.1 API介绍

org.springframework.jdbc.core.JdbcTemplate类方便执行SQL语句

  1. public int update(final String sql)
    用于执行`INSERT`、`UPDATE`、`DELETE`等DML语句。
    
2.3.2 使用步骤

1.创建JdbcTemplate对象
2.编写SQL语句
3.使用JdbcTemplate对象的update方法进行增删改

2.3.3 案例代码
public class Demo05 {
	public static void main(String[] args) throws Exception {
//		test01();
//		test02();
//		test03();
	}
	
	// JDBCTemplate添加数据
	public static void test01() throws Exception {
		JdbcTemplate jdbcTemplate = new JdbcTemplate(JdbcUtils.getDataSource());
		
		String sql = "INSERT INTO product VALUES (NULL, ?, ?);";
		
		jdbcTemplate.update(sql, "iPhone3GS", 3333);
		jdbcTemplate.update(sql, "iPhone4", 5000);
		jdbcTemplate.update(sql, "iPhone4S", 5001);
		jdbcTemplate.update(sql, "iPhone5", 5555);
		jdbcTemplate.update(sql, "iPhone5C", 3888);
		jdbcTemplate.update(sql, "iPhone5S", 5666);
		jdbcTemplate.update(sql, "iPhone6", 6666);
		jdbcTemplate.update(sql, "iPhone6S", 7000);
		jdbcTemplate.update(sql, "iPhone6SP", 7777);
		jdbcTemplate.update(sql, "iPhoneX", 8888);
	}
	
	
	// JDBCTemplate修改数据
	public static void test02() throws Exception {
		JdbcTemplate jdbcTemplate = new JdbcTemplate(JdbcUtils.getDataSource());
		
		String sql = "UPDATE product SET pname=?, price=? WHERE pid=?;";
		
		int i = jdbcTemplate.update(sql, "XVIII", 18888, 10);
		System.out.println("影响的行数: " + i);
	}

	// JDBCTemplate删除数据
	public static void test03() throws Exception {
		JdbcTemplate jdbcTemplate = new JdbcTemplate(JdbcUtils.getDataSource());
		String sql = "DELETE FROM product WHERE pid=?;";
		int i = jdbcTemplate.update(sql, 7);
		System.out.println("影响的行数: " + i);
	}
}
2.3.4 案例效果
  1. 增加数据效果
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sAQaIv7g-1582252345100)(imgs\连接池15.png)]
  2. 修改数据效果
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Mblxe9md-1582252345100)(imgs\连接池16.png)]
  3. 删除数据效果
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kb3ElIfo-1582252345101)(imgs\连接池17.png)]
2.3.5 总结

JdbcTemplate的update方法用于执行DML语句。同时还可以在SQL语句中使用?占位,在update方法的Object... args可变参数中传入对应的参数。

2.4 JdbcTemplate实现查询

org.springframework.jdbc.core.JdbcTemplate类方便执行SQL语句

2.4.1 queryForInt返回一个整数

2.4.1.1 API介绍
  1. public int queryForInt(String sql)
    执行查询语句,返回一个int类型的值。
    
2.4.1.2 使用步骤
  1. 创建JdbcTemplate对象
  2. 编写查询的SQL语句
  3. 使用JdbcTemplate对象的queryForInt方法
  4. 输出结果
2.4.1.3 案例代码
// queryForInt返回一个整数
public static void test01() throws Exception {
   // String sql = "SELECT COUNT(*) FROM product;";
   String sql = "SELECT pid FROM product WHERE price=18888;";
   JdbcTemplate jdbcTemplate = new JdbcTemplate(JdbcUtils.getDataSource());
   int forInt = jdbcTemplate.queryForInt(sql);
   System.out.println(forInt);
}
2.4.1.4 案例效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TYfYuQek-1582252345101)(imgs\连接池19.png)]

2.4.2 queryForLong返回一个long类型整数

2.6.2.1 API介绍
  1. public long queryForLong(String sql)
    执行查询语句,返回一个long类型的数据。
    
2.4.2.2 使用步骤
  1. 创建JdbcTemplate对象
  2. 编写查询的SQL语句
  3. 使用JdbcTemplate对象的queryForLong方法
  4. 输出结果
2.4.2.3 案例代码
// queryForLong  返回一个long类型整数
public static void test02() throws Exception {
   String sql = "SELECT COUNT(*) FROM product;";
   // String sql = "SELECT pid FROM product WHERE price=18888;";
   JdbcTemplate jdbcTemplate = new JdbcTemplate(JdbcUtils.getDataSource());
   long forLong = jdbcTemplate.queryForLong(sql);
   System.out.println(forLong);
}
2.4.2.4 案例效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hCaTtebM-1582252345101)(imgs\连接池20.png)]

2.4.3 queryForObject返回String

2.4.3.1 API介绍
  1. public <T> T queryForObject(String sql, Class<T> requiredType)
    执行查询语句,返回一个指定类型的数据。
    
2.4.3.2 使用步骤
  1. 创建JdbcTemplate对象
  2. 编写查询的SQL语句
  3. 使用JdbcTemplate对象的queryForObject方法,并传入需要返回的数据的类型
  4. 输出结果
2.4.3.3 案例代码
public static void test03() throws Exception {
   String sql = "SELECT pname FROM product WHERE price=7777;";
   JdbcTemplate jdbcTemplate = new JdbcTemplate(JdbcUtils.getDataSource());
   String str = jdbcTemplate.queryForObject(sql, String.class);
   System.out.println(str);
}
2.4.3.4 案例效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oC0Sp38b-1582252345102)(imgs\连接池21.png)]

2.4.4 queryForMap返回一个Map集合对象

2.4.4.1 API介绍
  1. public Map<String, Object> queryForMap(String sql)
    执行查询语句,将一条记录放到一个Map中。
    
2.4.4.2 使用步骤
  1. 创建JdbcTemplate对象
  2. 编写查询的SQL语句
  3. 使用JdbcTemplate对象的queryForMap方法
  4. 处理结果
2.4.4.3 案例代码
public static void test04() throws Exception {
   String sql = "SELECT * FROM product WHERE pid=?;";
   JdbcTemplate jdbcTemplate = new JdbcTemplate(JdbcUtils.getDataSource());
   Map<String, Object> map = jdbcTemplate.queryForMap(sql, 6);
   System.out.println(map);
}
2.4.4.4 案例效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Vl5cGo7c-1582252345102)(imgs\连接池22.png)]

2.4.5 queryForList返回一个List集合对象,集合对象存储Map类型数据

2.4.5.1 API介绍
  1. public List<Map<String, Object>> queryForList(String sql)
    执行查询语句,返回一个List集合,List中存放的是Map类型的数据。
    
2.4.5.2 使用步骤
  1. 创建JdbcTemplate对象
  2. 编写查询的SQL语句
  3. 使用JdbcTemplate对象的queryForList方法
  4. 处理结果
2.4.5.3 案例代码
public static void test05() throws Exception {
   String sql = "SELECT * FROM product WHERE pid<?;";
   JdbcTemplate jdbcTemplate = new JdbcTemplate(JdbcUtils.getDataSource());
   List<Map<String, Object>> list = jdbcTemplate.queryForList(sql, 8);
   for (Map<String, Object> map : list) {
      System.out.println(map);
   }
}
2.4.5.4 案例效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8uptXvfL-1582252345102)(imgs\连接池23.png)]

2.4.6 query使用RowMapper做映射返回对象

2.4.6.1 API介绍
  1. public <T> List<T> query(String sql, RowMapper<T> rowMapper)
    执行查询语句,返回一个List集合,List中存放的是RowMapper指定类型的数据。
    
2.4.6.2 使用步骤
  1. 定义Product类
  2. 创建JdbcTemplate对象
  3. 编写查询的SQL语句
  4. 使用JdbcTemplate对象的query方法,并传入RowMapper匿名内部类
  5. 在匿名内部类中将结果集中的一行记录转成一个Product对象
2.4.6.3 案例代码
// query使用rowMap做映射返回一个对象
public static void test06() throws Exception {
    JdbcTemplate jdbcTemplate = new JdbcTemplate(JdbcUtils.getDataSource());

   // 查询数据的SQL语句
   String sql = "SELECT * FROM product;";

   List<Product> query = jdbcTemplate.query(sql, new RowMapper<Product>() {
      @Override
      public Product mapRow(ResultSet arg0, int arg1) throws SQLException {
         Product p = new Product();
         p.setPid(arg0.getInt("pid"));
         p.setPname(arg0.getString("pname"));
         p.setPrice(arg0.getDouble("price"));
         return p;
      }
   });

   for (Product product : query) {
      System.out.println(product);
   }
}
2.4.6.4 案例效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9cgiv0Tl-1582252345102)(imgs\连接池18.png)]

2.4.7 query使用BeanPropertyRowMapper做映射返回对象

2.4.7.1 API介绍
  1. public <T> List<T> query(String sql, RowMapper<T> rowMapper)
    执行查询语句,返回一个List集合,List中存放的是RowMapper指定类型的数据。
    
  2. public class BeanPropertyRowMapper<T> implements RowMapper<T>
    BeanPropertyRowMapper类实现了RowMapper接口
    
2.4.7.2 使用步骤
  1. 定义Product类
  2. 创建JdbcTemplate对象
  3. 编写查询的SQL语句
  4. 使用JdbcTemplate对象的query方法,并传入BeanPropertyRowMapper对象
2.4.7.3 案例代码
	// query使用BeanPropertyRowMapper做映射返回对象
	public static void test07() throws Exception {
		JdbcTemplate jdbcTemplate = new JdbcTemplate(JdbcUtils.getDataSource());

		// 查询数据的SQL语句
		String sql = "SELECT * FROM product;";
		List<Product> list = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Product.class));

		for (Product product : list) {
			System.out.println(product);
		}
	}
2.4.6.4 案例效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8AvyBTMY-1582252345103)(imgs\连接池18.png)]

2.4.8 总结

JDBCTemplate的query方法用于执行SQL语句,简化JDBC的代码。同时还可以在SQL语句中使用占位,在query方法的Object... args可变参数中传入对应的参数。

第3章 三层架构

3.1 分层的作用

我们之前的登录案例是将用户输入,数据库的操作,逻辑处理放在了同一个方法中,这样虽然非常直观,但是等项目做大的时候非常不好维护代码,也不好增加功能。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-avE2PAXc-1582252345103)(imgs\分层01.png)]

分层介绍:
公司中分层:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MiefKxSl-1582252345103)(imgs\分层00.png)]

软件中分层:按照不同功能分为不同层,通常分为三层:表示层,业务层,数据访问层。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wwzMNK1t-1582252345103)(imgs\分层03.png)]

分层的作用:
1. 解耦:降低层与层之间的耦合性。
2. 可维护性:提高软件的可维护性,对现有的功能进行修改和更新时不会影响原有的功能。
3. 可扩展性:提升软件的可扩展性,添加新的功能的时候不会影响到现有的功能。
4. 可重用性:不同层之间进行功能调用时,相同的功能可以重复使用。

分层的方法:不同层次使用不同的包。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jTa4Q3SQ-1582252345103)(imgs\分层04.png)]

开发步骤:
从下向上开发:dao数据访问层 -> service业务逻辑层 -> view表示层

3.2 使用三层架构实现用户注册案例

3.2.1 案例需求

使用分层实现用户注册案例

3.2.2 案例效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Uy14O2pV-1582252345104)(imgs\分层05.png)]

3.2.3 案例分析

  1. 使用数据库保存用户的账号和密码
  2. 定义User类
  3. 编写DAO层,增加saveUserfindUser方法
  4. 编写业务层增加registerisExist方法
  5. 编写View层增加register方法

3.2.4 实现步骤

  1. 使用数据库保存用户的账号和密码,创建user表保存账号密码
CREATE TABLE `user` (
	uid INT PRIMARY KEY AUTO_INCREMENT,
	uname VARCHAR(20),
	upasswd VARCHAR(20)
);

INSERT INTO `user` (uname, upasswd) VALUES ('abc', '123');
INSERT INTO `user` (uname, upasswd) VALUES ('efg', '123');
INSERT INTO `user` (uname, upasswd) VALUES ('admin', '123');
  1. 定义User类
/**
 * 用户类
 *
 */
public class User {
	private int uid;
	private String uname;
	private String upasswd;

	public int getUid() {
		return uid;
	}

	public void setUid(int uid) {
		this.uid = uid;
	}

	public String getUname() {
		return uname;
	}

	public void setUname(String uname) {
		this.uname = uname;
	}

	public String getUpasswd() {
		return upasswd;
	}

	public void setUpasswd(String upasswd) {
		this.upasswd = upasswd;
	}

	public User(int uid, String uname, String upasswd) {
		super();
		this.uid = uid;
		this.uname = uname;
		this.upasswd = upasswd;
	}

	public User(String uname, String upasswd) {
		super();
		this.uname = uname;
		this.upasswd = upasswd;
	}

	public User() {
		super();
	}

	@Override
	public String toString() {
		return "User [uid=" + uid + ", uname=" + uname + ", upasswd=" + upasswd + "]";
	}
}
  1. 编写DAO层,增加saveUserfindUser方法
public class UserDao {

	JdbcTemplate jdbcTemplate = new JdbcTemplate(DataSourceUtils.getDataSource());

	// 保存用户到数据库
	public int saveUser(User user) {
		try {
			return jdbcTemplate.update("INSERT INTO user (uname, upasswd) values (?, ?);", user.getUname(), user.getUpasswd());
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

	// 从数据库查询是否有相同的记录
	public User findUser(String uname) {
		try {
			String sql = "SELECT * FROM user WHERE uname = ?;";
			// 注意:queryForObject如果没有找到数据,不是返回null,而是抛出异常,所以捕获异常,返回null
			return jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), uname);
		} catch (Exception e) {
			return null;
		}
	}
}
  1. 编写业务层增加registerisExist方法
/**
 * 业务层
 *
 */
public class UserService {

	private UserDao userDao = new UserDao();

	/**
	 * 注册
	 */
	public boolean register(User user) {
		// 保存用户信息到数据库
		return userDao.saveUser(user) > 0;
	}

	/**
	 * 判断用户是否存在
	 */
	public boolean isExist(String name) {
		return userDao.findUser(name) != null;
	}
}
  1. 编写View层增加register方法
/*
    view表示层
 */
public class UserSystem {
    private static UserService userService = new UserService();
    private static Scanner scanner = new Scanner(System.in);

    public static void main(String[] args) {
        System.out.println("-- 欢迎使用 --");
        while (true) {
            // 循环注册,知道注册成功才结束
            if (register()) {
                break;
            }
        }
    }

    /**
     * 注册的方法
     */
    private static boolean register() {
        System.out.println("请输入注册信息:");
        System.out.println("用户名:");
        String name = scanner.next();
        if (userService.isExist(name)) {
            System.out.println("用户名已经存在");
            return false;
        }
        System.out.println("密码:");
        String password = scanner.next();
        //封装数据
        User user = new User(name, password);
        if (userService.register(user)) {
            System.out.println("注册成功");
            return true;
        } else {
            System.out.println("注册失败");
            return false;
        }
    }
}

3.2.5 总结

当我们使用分层后,修改代码很方便,假如SQL语句写的有问题,只需要修改DAO层。使用分层后,增加功能也很方便,比如增加登录功能,在视图层增加登录的界面,在业务层增加登录的逻辑,DAO层直接使用原有代码。

分层的作用:
1. 解耦:降低层与层之间的耦合性。
2. 可维护性:提高软件的可维护性,对现有的功能进行修改和更新时不会影响原有的功能。
3. 可扩展性:提升软件的可扩展性,添加新的功能的时候不会影响到现有的功能。
4. 可重用性:不同层之间进行功能调用时,相同的功能可以重复使用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值