dao--2.dao模式

xiaoxiao2021-02-28  123

1      DAO模式

1.1  概述

         DAO模式(DataAccess Object 数据访问对象):在持久层通过DAO将数据源操作完全封装起来,业务层通过操作Java对象,完成对数据源操作

         业务层无需知道数据源底层实现 ,通过java对象操作数据源

       DAO模式实际上是两个模式的组合,即Data Accessor模式和Active Domain Object模式,前者实现了数据访问和业务逻辑的分离,后者实现了业务数据的对象化封装。

 

DAO模式通过对业务层提供数据抽象层接口,实现了以下目标:

       -数据存储逻辑的分离(业务层不会出现SQL语句和JDBC代码)

       -数据访问底层实现的分离(底层可以是数据库、文件系统、云存储服务等)

       -资源管理和调度的分离(通过连接池、缓存提升性能而不影响上层系统)

       -数据抽象(操作对象而不是数据字段使得业务逻辑更加清晰)

 

因此,DAO = Data+ Accessor + (Domain) Object

1.2  图解

 

2      PreparedStatement接口

2.1  SQL注入

         由于没有对用户输入进行充分检查,而SQL又是拼接而成,在用户输入参数时,在参数中添加一些SQL 关键字,达到改变SQL运行结果的目的,也可以完成恶意攻击。

 

String sql = select * from user whereusername ='' and password ='' ;

 

例如:

一、输入 username: 老李' or '1'='1    password 随意

select * from user where username ='老李' or'1'='1' and password ='';

         and优先级 执行 高于 or

 

SQL注入原理是什么?

         1.在输入时连接一个永远为真的一个值

         2.使用mysql 中的 – 注释

为什么PreparedStatement 可以防止SQL注入?

         因为它对sql语句进行预编译。

 

 

2.2  解决SQL注入--预编译

         使用PreparedStatement取代 Statement

         PreparedStatement解决SQL注入原理,运行在SQL中参数以?占位符的方式表示

select * from user where username = ? andpassword = ? ;

 

原理:

         将带有?的SQL 发送给数据库完成编译 (不能执行的SQL 带有?的SQL 进行编译 叫做),在SQL编译后发现缺少两个参数PreparedStatement可以将? 代替参数发送给数据库服务器,因为SQL已经编译过,参数中特殊字符不会当做特殊字符编译,无法达到SQL注入的目的

 

问题:

 

2.3  PreparedStatement接口

2.3.1  定义sql语句

2.3.2  创建命令对象

 

2.3.3  命令对象执行sql语句

 

2.3.4  批处理操作

 

 

3      ResultSet 高级应用 ---- 滚动结果集

3.1  初始化

         设置结果集类型,并发策略

 

3.2  三种组合

 

4      JdbcUtils抽取方式1

4.1  jdbc.properties

 

driverClass=com.mysql.jdbc.Driver url=jdbc:mysql:///day17 username=root password=abc 

4.2  JdbcUtils

public classJdbcUtils { private static final String DRIVERCLASS; private static final String URL; private static final String USERNAME; private static final String PASSWORD; static { DRIVERCLASS =ResourceBundle.getBundle("jdbc").getString("driverClass"); URL = ResourceBundle.getBundle("jdbc").getString("url"); USERNAME =ResourceBundle.getBundle("jdbc").getString("username"); PASSWORD =ResourceBundle.getBundle("jdbc").getString("password"); } static { try { // 将加载驱动操作,放置在静态代码块中.这样就保证了只加载一次. Class.forName(DRIVERCLASS); }catch(ClassNotFoundException e) { e.printStackTrace(); } } public static ConnectiongetConnection() throwsSQLException { // 2.获取连接 Connectioncon = DriverManager.getConnection(URL, USERNAME, PASSWORD); return con; } //关闭操作 public static voidcloseConnection(Connection con) throws SQLException{ if(con!=null){ con.close(); } } public static voidcloseStatement(Statement st) throws SQLException{ if(st!=null){ st.close(); } } public static voidcloseResultSet(ResultSet rs) throws SQLException{ if(rs!=null){ rs.close(); } } }

4.3  dao

 

public classUserDaoImpl implements UserDao{ // 查找用户---使用Statement完成登录操作,存在风险(sql注入) public User _findUser(Useruser) throwsSQLException { // 1.sql语句 Stringsql = "select * from user whereusername='" + user.getUsername() +"' and password='" + user.getPassword() + "'"; // 2.执行sql Connectioncon = null; Statementst = null; ResultSetrs = null; try { con= JdbcUtils.getConnection(); st= con.createStatement(); rs= st.executeQuery(sql); if (rs.next()) { // 如果可以next,代表查找到了这个用户的信息,就将结果集中的信息封装到User对象中. Useru = newUser(); u.setId(rs.getInt("id")); u.setUsername(rs.getString("username")); u.setPassword(rs.getString("password")); u.setEmail(rs.getString("email")); return u; } }finally{ try { JdbcUtils.closeResultSet(rs); JdbcUtils.closeStatement(st); JdbcUtils.closeConnection(con); }catch(SQLException e) { e.printStackTrace(); } } return null; } // 使用PreparedStatement来完成操作,它可以解决sql注入. public User findUser(Useruser) throwsSQLException { // 1.sql语句 Stringsql = "select * from user where username=?and password=?"; // 2.执行sql Connectioncon = null; PreparedStatementpst = null; ResultSetrs = null; try { con= JdbcUtils.getConnection(); pst= con.prepareStatement(sql); pst.setString(1,user.getUsername()); pst.setString(2,user.getPassword()); rs= pst.executeQuery();// 无参数 if (rs.next()) { // 如果可以next,代表查找到了这个用户的信息,就将结果集中的信息封装到User对象中. Useru = newUser(); u.setId(rs.getInt("id")); u.setUsername(rs.getString("username")); u.setPassword(rs.getString("password")); u.setEmail(rs.getString("email")); return u; } }finally { try { JdbcUtils.closeResultSet(rs); JdbcUtils.closeStatement(pst); JdbcUtils.closeConnection(con); }catch(SQLException e) { e.printStackTrace(); } } return null; } } 

5      JdbcUtils抽取方式2

5.1  jdbc.properties

jdbc.driver = com.mysql.jdbc.Driver jdbc.url = jdbc:mysql://127.0.0.1:3306/user?useUnicode=true&characterEncoding=UTF-8 jdbc.user = root jdbc.password = root

5.2  JdbcUtil

public classJdbcUtil { private static String driver; private static String url; private static String user; private static String password; static { /** * 输入流 */ InputStreamin = JdbcUtil.class.getClassLoader().getResourceAsStream("jdbc.properties"); Propertiesproperties= newProperties(); try { //将输入流加载到配置文件的 properties.load(in); }catch(IOException e) { System.out.println("jdbc.properties加载失败"); e.printStackTrace(); } //读取配置文件参数 driver = properties.getProperty("jdbc.driver"); url = properties.getProperty("jdbc.url"); user = properties.getProperty("jdbc.user"); password = properties.getProperty("jdbc.password"); } static { try { //注册驱动 Class.forName(driver); }catch(ClassNotFoundException e) { System.out.println("注册驱动失败"); e.printStackTrace(); } } /** * 创建连接 * @return */ public static ConnectiongetConnection(){ try { return DriverManager.getConnection(url, user, password); }catch(SQLException e) { System.out.println("创建数据库连接失败"); e.printStackTrace(); return null; } } public static void release(Connection conn,Statement stmt) { if (stmt != null) { try { stmt.close(); }catch(SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if (conn != null) { try { conn.close(); }catch(SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public static void release(Connection conn,PreparedStatement pstmt) { if (pstmt != null) { try { pstmt.close(); }catch(SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if (conn != null) { try { conn.close(); }catch(SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public static void release(Connection conn,Statement stmt , ResultSet res) { if (res != null) { try { res.close(); }catch(SQLException e) { System.out.println("关闭ResultSet失败"); e.printStackTrace(); } } if (stmt != null) { try { stmt.close(); }catch(SQLException e) { System.out.println("关闭Statement失败"); e.printStackTrace(); } } if (conn != null) { try { conn.close(); }catch(SQLException e) { System.out.println("关闭Connection失败"); e.printStackTrace(); } } } public static void release(Connection conn,PreparedStatement pstmt , ResultSet res) { if (res != null) { try { res.close(); }catch(SQLException e) { System.out.println("关闭ResultSet失败"); e.printStackTrace(); } } if (pstmt != null) { try { pstmt.close(); }catch(SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if (conn != null) { try { conn.close(); }catch(SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }

5.3  Dao

 

public ArrayList<Car> seleteAll() { Connectionconn= JdbcUtil.getConnection(); Stringsql= "select * from car"; PreparedStatementpstmt; ResultSetres; ArrayList<Car>list= null; try { pstmt = conn.prepareStatement(sql); res = pstmt.executeQuery(); list = newArrayList<>(); while (res.next()){ Carcar= newCar(); car.setId(res.getInt(1)); car.setName(res.getString(2)); car.setType(res.getString(3)); car.setPrice(res.getDouble(4)); list.add(car); } JdbcUtil.release(conn, pstmt, res); }catch(SQLException e) { e.printStackTrace(); } return list; }  

6      JDBC进行批处理

6.1  概念

         业务场景:当需要向数据库发送一批SQL语句执行时,应避免向数据库一条条的发送执行,而应采用JDBC的批处理机制,以提升执行效率。

         一次执行多条sql语句

 

6.2  第一种方式—Statement

6.2.1  方法

6.2.2  示例

public class StatementBatchTest { publicstatic void main(String[] args) throws SQLException { //定义sql语句 Stringsql1 = "create table person(id int,name varchar(20))"; Stringsql2 = "insert into person values(1,'tom')"; Stringsql3 = "insert into person values(2,'fox')"; Stringsql4 = "insert into person values(3,'tony')"; Stringsql5 = "update person set name='张三' where id=1"; Stringsql6 = "delete from person where id=3"; Connectioncon = JdbcUtils.getConnection(); //得到一个Statement对象 Statementst = con.createStatement(); //使用批处理执行sql st.addBatch(sql1); st.addBatch(sql2); st.addBatch(sql3); st.addBatch(sql4); st.addBatch(sql5); st.addBatch(sql6); //执行批处理 st.executeBatch(); st.close(); con.close(); } }  

 

6.3  第二种方式—PreparedStatement

6.3.1  方法

 

6.3.2  示例

 

public class PreparedStatementBatchTest { publicstatic void main(String[] args) throws SQLException { //向person表中插入1000条数据 Stringsql = "insert into person values(?,?)"; Connectioncon = JdbcUtils.getConnection(); PreparedStatementpst = con.prepareStatement(sql); //批处理 longl=System.currentTimeMillis(); for(int i = 1; i <= 100000; i++) { pst.setInt(1,i); pst.setString(2,"name" + i); pst.addBatch(); if(i00==0){ pst.executeBatch(); pst.clearBatch();//清空缓存。 } } //执行批处理 pst.executeBatch(); pst.close(); con.close(); System.out.println(System.currentTimeMillis()-l); } } 

6.4  运用场景

 

 

 

 源代码文件:http://download.csdn.net/detail/qq_26553781/9835515

 

 

 

 

 

 

 

转载请注明原文地址: https://www.6miu.com/read-68233.html

最新回复(0)