[email protected] DAO,数据访问层(持久化层)

DAO设计模式

DAO:Data Access Object,数据访问对象,主要的功能就是进行数据库数据的操作,模拟出企业的开发架构:
- 客户层:浏览器
- 显示层:使用jsp/Servlet/html进行页面效果显示
- 控制层:使用Servlet完成,是连接显示层和业务层
- 业务层:service层,具体进行业务处理,是连接控制层和持久化层,并且进行一些业务的处理,比如事务等
- 持久化层:也叫作数据访问层,JDBC完成
- 数据库:MySQL/Oracle
- 以后的开发中,在jsp页面中,是绝对不允许再出现导入java.sql包的;
一个DAO实际上就是一个JavaBean的组件模型。

DAO:DataBase Access Object,数据库访问对象,数据库表(或视图)中的每一笔数据就是实体类的一个对象,实体类中的属性就是数据表中的字段,这个类我们就叫做实体类,也叫作对象关系映射类(这个类的每一个对象都可以映射到数据表的一笔数据,ORM)。

DAO中会使用到的其他的设计模式有静态工厂模式和代理模式。DAO的组成:

1.实体类(entities):数据库表或视图中的每一笔数据就是实体类的一个对象,一个表或视图就是一个实体类,实体类的命名使用表名的大驼峰命名。属性名使用小驼峰命名。

2.Dao接口:定义一组数据库表增删改查的操作,只需要声明,不需要实现,接口名称的命名规则:实体类名Dao

接口中方法的命名规则

​ - 新增 : insert 或者 add

​ - 修改 : update 或者updateByXxx

​ - 删除:delete 或者deleteByXxx

​ - 查询:

​ - getXxxByXxx或者findXxxByXxx,比如根据名称查询学生信息: getStudentInfoByStuName/findStudentInfoByStuName
- 查询 : selectXxxByXxx或者getXxxByXxx,比如我们根据学生名称模糊查询学生信息(selectStudentByStuNameLike(String stuName))
​ - 根据书号查询图书的信息 getBooksByBookId

​ - 根据图书名称模糊查询图书信息:getBooksByBookNameLike

3.Dao接口的实现类:真实主题类,实现Dao接口中所有声明的方法,具体去完成增删改查操作,但是不关注数据库连接的取得和关闭,Dao接口实现类命名规则:Dao接口名Imp |Dao接口名Impl

33 代理实现类[丢弃]:实现Dao接口,代理真实主题类完成数据库连接的取得和关闭,并且调用真实主题类,命名规则:Dao名称Proxy
[因为开发需要使用事务技术,而事务又是在service层进行操作,所以数据库连接的取得和关闭都放在业务层]

4.Dao工厂类:有接口就需要使用工厂,工厂类的作用是用来完成接口对象生产,以便于service层的调用。工厂的作用就是返回Dao的实例对象。

生产Dao接口对象的,一般使用静态工厂方法生产Dao对象,工厂类的命名规则:

Dao接口名Factory,静态工厂方法名:get接口名Instance,静态方法中return返回接口的对象。

总结:

Dao层包括,实体类,Dao接口,Dao接口实现类,Dao接口的代理实现类(取得数据库的连接和关闭),工厂类(生产接口对象)

每一张表或者一个视图都会存在一个Dao。之前数据库的连接和关闭放在代理实现类,加了事务后数据库的连接和关闭放在业务实现类层。

数据库表中的一笔数据,就是实体类的一个对象,实体类中的属性就是数据表中的字段。

DAO设计模式(数据访问对象),并不是java23种设计模式的一种,因为它在所有语言都可以使用,DAO设计模式需要使用到静态工厂和代理模式这两种模式拼凑在一起。

工厂方法模式:实现类与类之间充分的解耦合操作,比如我们之前在类中直接实例化另外一个类的对象,我们说这个耦合度就很高,导致程序的可维护性降低。

A类:

B类:需要实例化A类对象。

直接调用A类构造器,需要知道A类构造器要什么参数,要知道A类构造器如何编写的,然后通过new去创造这个对象,这种方式对B类要求很高,相当于需要一个斧头,必须知道这个斧头的制造过程,才能拥有这把斧头。

这是原始社会用斧头操作,自己做斧头。封建社会要用斧头去铁匠铺买斧头,去买斧头,这个铁匠铺就相当于生产斧头的工厂。

工厂方法模式就是,去搞一个生产对象的工厂,B类要拿到A类对象,不需要完全的了解A类到底有什么样的构造器,要创造它的对象,而只需要去工厂拿,调用工厂的方法去拿就行了。

使用工厂方法之后,相当于从原始社会过渡到了封建社会,在原始社会需要一个对象,必须知道这个对象所对应的类型中构造器是如何定义的,如何传递参数的,才能够获取到想要的类的对象,在封建社会,我们不关注对象的产生,而是将对象产生的过程交给工厂去完成,需要这个对象的地方只要调用工厂方法就可以获取想要的对象。

静态工厂:工厂类中提供的获取对象的方法是静态的。(用的多)

实例工厂:工厂类中提供的获取对象的方法是非静态的。

代理模式:要完成一个操作,主要的内容是A完成的,有一部分是B帮助A完成的,这个时候B就是代理A完成了一些工作。

一个接口两个类,A是真实主题类,B是代理类。真实主题类和代理类都需要去实现接口,而且需要在代理类中获取真实主题类的对象,并且调用真实主题类中的方法,就是在B类中获取A类的对象,并且调用A中的方法。

后台三层架构

1.控制层:原生开发:Servlet,框架开发: Struts2(Action)SpringMVC(Handler)

2.业务层:service层,处理实际的业务,调用一个或者多个Dao,一个业务就是一个service

Service层包括,Service接口和接口实现类。

3.数据访问层(持久化层):Dao层,完成数据库实际的增删改查操作

Dao层包括,实体类,Dao接口,Dao接口实现类,工厂类(生产接口对象)
总结:先来三个包名,com.wanbangee.dao com.wanbangee.service com.wanbangee.controller
在dao包中先建entities实体类(一个表或视图就是一个实体类,set和get方法,有参和无参构造器),dao , daoimp, daoproxy(丢弃), daofactory

案例:买书

数据库(book)有三张表:

图书信息表(books,有3个字段,book_id,book_name,price),

图书库存表(book_stock,有3个字段,book_id,book_name,stock),

账户余额表(account,有3个字段,loginname,loginpass,balance),

需要完成的买书业务,买书的过程:1 查询图书单价。2 减少账户余额。3 减少图书库存

对于增删改来说,一定要进行事务的管理。

这三个操作要么全部成功要么全部失败,所以必须加事务,而且事务应该加在业务层。

注意:异常的处理放在业务层,如果在数据库访问层(Dao层)处理异常,那么业务层的事务将会失效。

实体类:

package com.wanbangee.entities;

public class Account {
	private String loginname;
	private String loginpass;
	private double balance;
	public String getLoginname() {
		return loginname;
	}
	public void setLoginname(String loginname) {
		this.loginname = loginname;
	}
	public String getLoginpass() {
		return loginpass;
	}
	public void setLoginpass(String loginpass) {
		this.loginpass = loginpass;
	}
	public double getBalance() {
		return balance;
	}
	public void setBalance(double balance) {
		this.balance = balance;
	}
	public Account(String loginname, String loginpass, double balance) {
		super();
		this.loginname = loginname;
		this.loginpass = loginpass;
		this.balance = balance;
	}
	public Account() {
		super();
		// TODO Auto-generated constructor stub
	}
	@Override
	public String toString() {
		return "Account [loginname=" + loginname + ", loginpass=" + loginpass + ", balance=" + balance + "]";
	}
	
	
}
package com.wanbangee.entities;

public class Books {
	private int bookId;
	private String bookName;
	private double price;
	public int getBookId() {
		return bookId;
	}
	public void setBookId(int bookId) {
		this.bookId = bookId;
	}
	public String getBookName() {
		return bookName;
	}
	public void setBookName(String bookName) {
		this.bookName = bookName;
	}
	public double getPrice() {
		return price;
	}
	public void setPrice(double price) {
		this.price = price;
	}
	public Books(int bookId, String bookName, double price) {
		super();
		this.bookId = bookId;
		this.bookName = bookName;
		this.price = price;
	}
	public Books() {
		super();
		// TODO Auto-generated constructor stub
	}
	@Override
	public String toString() {
		return "Books [bookId=" + bookId + ", bookName=" + bookName + ", price=" + price + "]";
	}
	
	
}
package com.wanbangee.entities;

public class BookStock {
private int bookId;
private String bookName;
private int stock;
public int getBookId() {
	return bookId;
}
public void setBookId(int bookId) {
	this.bookId = bookId;
}
public String getBookName() {
	return bookName;
}
public void setBookName(String bookName) {
	this.bookName = bookName;
}
public int getStock() {
	return stock;
}
public void setStock(int stock) {
	this.stock = stock;
}
public BookStock(int bookId, String bookName, int stock) {
	super();
	this.bookId = bookId;
	this.bookName = bookName;
	this.stock = stock;
}
public BookStock() {
	super();
	// TODO Auto-generated constructor stub
}
@Override
public String toString() {
	return "BookStock [bookId=" + bookId + ", bookName=" + bookName + ", stock=" + stock + "]";
}

}

Dao接口:

package com.wanbangee.dao;

public interface AccountDao {
//谁买书谁减少余额,根据买书人名字减少余额,减少的余额就是所买书的单价,一次买一本书
	public void doUpdate(String loginname,double price);
}
package com.wanbangee.dao;

public interface BooksDao {
//根据图书ID查询图书价格
	public Double getPriceByBookId(int bookId);
}
package com.wanbangee.dao;

public interface BookStockDao {
//减少所买图书库存
	public void doUpdate(int bookId);
}

Dao接口实现类:

package com.wanbangee.dao.imp;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import com.wanbangee.dao.AccountDao;

public class AccountDaoImp implements AccountDao {
/*真实主题类,实现Dao接口中所有声明的方法,
 具体去完成增删改查操作,但是不关注数据库连接的取得和关闭*/
	//1先定义数据库连接对象,但这里不连接
	Connection conn ;
	//现在没有连接数据库,这个数据库连接对象conn是空的,空的要是执行增删改查会报错
	//谁调我谁负责把连接拿过来,谁调我,谁要去实例化我这个对象,就把数据库连接对象conn拿过来
	//谁要使用接口实现类的对象就必须将数据库连接对象conn传递进来
	//接口实现类本身没有去获取数据库连接,只是谁调用我谁给我
	public AccountDaoImp(Connection conn) {
		this.conn = conn;
	}
	
	//减少账户余额,是个修改操作
	@Override
	public void doUpdate(String loginname, double price) {
		PreparedStatement pstate = null;
		try { 
			String sql = "update account set balance = balance - ? where loginname = ? ";
			//pstate = conn.prepareStatement(sql);
			pstate = this.conn.prepareStatement(sql);
			pstate.setDouble(1, price);
			pstate.setString(2, loginname);
			pstate.execute();
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				pstate.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		
	}

}
package com.wanbangee.dao.imp;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import com.wanbangee.dao.BooksDao;

public class BooksDaoImp implements BooksDao {
	Connection conn;
	public BooksDaoImp(Connection conn) {
		this.conn = conn;
	}
	
	//查询图书的单价,是个查询操作
	@Override
	public Double getPriceByBookId(int bookId) {
		PreparedStatement pstate = null;
		ResultSet res = null;
		double price = 0;//定义图书价格,给个默认值0
		try {
			String sql = "select price from books where book_id = ?";
			//pstate = conn.prepareStatement(sql);
			pstate = this.conn.prepareStatement(sql);
			pstate.setInt(1, bookId);
			res = pstate.executeQuery();
			while(res.next()) {
				price = res.getDouble("price");
				//获得这一本的书价赋值给double price = 0;中的price变量,最后return返回price这个变量
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				res.close();
				pstate.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return price;//调用这个方法返回图书价格
	}

}
package com.wanbangee.dao.imp;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import com.wanbangee.dao.BookStockDao;

public class BookStockDaoImp implements BookStockDao {
Connection conn;//谁调我谁传数据库连接对象conn进来
public BookStockDaoImp(Connection conn) {
	this.conn = conn;
}
//每个接口实现类都是完成自己的业务,其它的代码都一样
	@Override//修改图书库存,是个修改操作,只需预处理对象,不用查询结果集
	public void doUpdate(int bookId) { //一次买一本书
		PreparedStatement pstate = null;
		try {
			String sql = "update book_stock set stock = stock -1 where book_id = ?";
			//pstate = conn.prepareStatement(sql);
			pstate = this.conn.prepareStatement(sql);
			pstate.setInt(1, bookId);
			pstate.execute();
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				pstate.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}

Dao工厂类:

package com.wanbangee.dao.factory;

import java.sql.Connection;

import com.wanbangee.dao.AccountDao;
import com.wanbangee.dao.imp.AccountDaoImp;

public class AccountDaoFactory {
	public static AccountDao getAccountDaoInstance(Connection conn) {
		return new AccountDaoImp(conn);
	}
}

package com.wanbangee.dao.factory;

import java.sql.Connection;

import com.wanbangee.dao.BooksDao;
import com.wanbangee.dao.imp.BooksDaoImp;

public class BooksDaoFactory {
	public static BooksDao getBooksDaoFactory(Connection conn) {
		return new BooksDaoImp(conn);
	}
}

package com.wanbangee.dao.factory;

import java.sql.Connection;

import com.wanbangee.dao.BookStockDao;
import com.wanbangee.dao.imp.BookStockDaoImp;

public class BookStockDaoFactory {
	public static BookStockDao getBookStockDaoInstance(Connection conn) {
		return new BookStockDaoImp(conn);
	}
}

业务层service接口:

package com.wanbangee.service;

public interface BuyBookService {
//买一本书,谁买哪本书
	public boolean buyBook(String loginname,int bookId);
}

业务实现类:数据库的连接和关闭放在业务实现类层

package com.wanbangee.service.imp;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import com.wanbangee.dao.factory.AccountDaoFactory;
import com.wanbangee.dao.factory.BookStockDaoFactory;
import com.wanbangee.dao.factory.BooksDaoFactory;
import com.wanbangee.jdbc.DBUtil;
import com.wanbangee.service.BuyBookService;

public class BuyBookServiceImp implements BuyBookService {
//数据库的连接和关闭放在业务层
	@Override
	public boolean buyBook(String loginname, int bookId) {
	    boolean flag = false;
		Connection conn = null;
		PreparedStatement pstate = null;
		ResultSet res = null;
/*买书的过程:
1 查询图书的单价
2 减少账户余额
3 减少图书库存
这三个操作要么全部成功要么全部失败,所以必须加事务,而且事务应该加在业务层。*/
		try {
			conn = DBUtil.getConnection();
			
		//1.取消事务的自动提交
		conn.setAutoCommit(false);	
			
			//1 查询图书的单价,单价在BooksDao,
			double price = BooksDaoFactory.getBooksFactoryInstance(conn).getPriceByBookId(bookId);
			//工厂类调用静态工厂方法获得接口对象,对象调用接口中的方法
			//2 减少账户余额
			AccountDaoFactory.getAccountDaoInstance(conn).doUpdate(loginname, price);
			//3 减少图书库存
			BookStockDaoFactory.getBookStockDaoInstance(conn).doUpdate(bookId);
		
		String sql = "select balance from account where loginname = ? ";
		pstate = conn.prepareStatement(sql);
		pstate.setString(1, loginname);
		res = pstate.executeQuery();
		while(res.next()) {
			if(res.getDouble("balance") < 0) {
				System.out.println(res.getDouble(1));
				throw new RuntimeException("余额不足");
			}else{
				System.out.println("余额够"+"==="+res.getDouble(1));
			}
		}
		
		
		String sql2 = "select stock from book_stock where book_id = ?";
		pstate = conn.prepareStatement(sql2);
		pstate.setInt(1, bookId);
		res = pstate.executeQuery();
		while(res.next()) {
			if(res.getInt("stock") < 0) {
				System.out.println(res.getInt(1));
				throw new RuntimeException("库存不足");
			}else {
				System.out.println("库存够"+"==="+res.getInt(1));
			}
		}
		
		
		//2.没有异常,提交事务
		conn.commit();
		flag = true;
			
		} catch (Exception e) {
		try {
			//3.出现异常,回滚事务
			conn.rollback();
			flag = false;
		} catch (SQLException e1) {
			e1.printStackTrace();
		}	
			e.printStackTrace();
		}finally {
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}	
		return flag;
	}
}

控制层servlet:

package com.wanbangee.servlet;

import com.wanbangee.service.BuyBookService;
import com.wanbangee.service.imp.BuyBookServiceImp;

public class BuyBookServlet {
	public static void main(String[] args) {
		String loginname = "jjm";
		int bookId = 1;
		
		BuyBookService  service = new BuyBookServiceImp();
		boolean flag = service.buyBook(loginname, bookId);
		if(flag == true) {
			System.out.println("买书成功");
		}else {
			System.out.println("买书失败");
		}
	}
}

使用JDBC调用函数和过程

使用JDBC调用函数:(调用函数和查询是一样的操作)

#在girls数据库中,创建函数myf1

DELIMITER $
CREATE FUNCTION myf1(m INT) RETURNS INT
BEGIN
	RETURN m*100;
END $
SELECT myf1(10);
package com.wanbangee.jdbc;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
//调用函数,和查询是一样的操作
public class Demo01 {
	public static void main(String[] args) {
		Connection conn = null;
		PreparedStatement pstate = null;
		ResultSet res = null;
		try {
			conn = DBUtil.getConnection();
			String sql ="SELECT myf1(10)";
			pstate = conn.prepareStatement(sql);//没有参数不用设置问号值
			res = pstate.executeQuery();
			while(res.next()) {
				System.out.println(res.getInt(1));
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				res.close();
				pstate.close();
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}

使用JDBC调用存储过程:

#在girls数据库中,创建存储过程myp4

DELIMITER $$

USE girls $$

DROP PROCEDURE IF EXISTS myp4 $$

CREATE DEFINER=root@localhost PROCEDURE myp4(IN user_name VARCHAR(20),IN pass_word VARCHAR(20),OUT res VARCHAR(10))
BEGIN
	DECLARE result INT;
	SELECT COUNT(*) INTO result FROM admin WHERE username = user_name
	AND PASSWORD = pass_word;
	SELECT IF(result>0,'success','fail') INTO res;
END$$

DELIMITER ;
CALL myp4('mpp','mpp123',@abc);

SELECT @abc;
package com.wanbangee.jdbc;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.JDBCType;
import java.sql.SQLException;

public class Demo02 {
	public static void main(String[] args) {
		Connection conn = null;
		CallableStatement cstate = null;
		try {
			conn = DBUtil.getConnection();
			String sql ="CALL myp4(?,?,?)";
			cstate = conn.prepareCall(sql);//获取CallableStatement对象
			cstate.setString(1, "mpp");
			cstate.setString(2, "mpp123");
			cstate.registerOutParameter(3, JDBCType.VARCHAR);//注册返回值的类型
			cstate.execute();
			String result = cstate.getString(3);//获取返回值
			System.out.println(result);
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				cstate.close();
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}	
		}
	}
}

DAO

DAO是数据访问层的操作,掌握DAO的各个组成部分及组成部分的代码编写;

DAO的执行顺序:DAOFactory —》DAOProxy—》DAOImpl;

一个DAO实际上就是一个JavaBean的组件模型。

DAO案例:买书程序

开发中,一个表或者一个视图就存在一个Dao

表图书信息表(图书ID,编号,名称,作者,单价,出版日期,出版社):Dao实现增删改查

账户表(账户ID,真实姓名,身份证号码,生日,性别,省份,城市,余额):Dao实现增删改查

图书库存表(图书ID,库存数量):Dao实现增删改查

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值