我们常常都在说三层架构,那么分为哪三层呢? 具体可以分为表示层、业务逻辑层和数据访问层。三层架构的中心思想就是业务逻辑层尽量不依赖于数据访问层的具体实现。
学了jdbc所用的数据库是mysql,写了一个简单的三层架构,能实现数据库的一般操作,就当是学习jdbc的一个练习,三层架构在以后的项目中也会用到,这里就只写个模板,以后自己可以参考。
在三层架构中,主要的源文件有:
数据库中Users表的创建:
create table users(
uid int primary key ,
upassword varchar(10) not null ,
uname varchar(10),
uscore float
) ;
domain对象:User类
domain对象就是数据访问层与业务逻辑层之间进行交互的对象,在这个例子中就是User。 User类在属性上跟数据库里面对于的表的属性要一样,毕竟数据库中对于的表要存放这个对象的信息。
public class User {
private int id ;//用户id
private String password ;//用户密码
private String name ;//用户姓名
private float score ;//用户成绩
public User(){
}
public User(int id,String password,String name,float score){
this.id = id ;
this.password = password ;
this.name = name ;
this.score = score ;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public float getScore() {
return score;
}
public void setScore(float score) {
this.score = score;
}
public String toString(){
return "id:"+id+"\t"+"password:"+password+"\t"+"name:"+name+"\t"+"score:"+score ;
}
}
数据库访问接口:UserDao接口
这个接口里面封装了对数据库的各种操作,如插入,查询,更新,删除等。
public interface UserDao {
//添加用户
public void addUser(User user) ;
//登陆
public User load(int id, String password) ;
//查找用户
public User findById(int id);
//更新用户
public void update(User user);
//删除用户
public void delete(int id);
//释放数据库资源
public void free() ;
}
数据库访问对象的jdbc实现:UserDaoJdbcImpl类
这个类需要实现UserDao接口,在这个类中去实现数据库的具体操作。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
//实现jdbc的数据库操作。
public class UserDaoJdbcImpl implements UserDao{
private static String url = "jdbc:mysql://localhost:3306/dxd" ;
private static String user = "root" ;
private static String password = "dxd123" ;
private static Connection conn = null ;
private PreparedStatement ps = null ;
private ResultSet rs = null ;
public UserDaoJdbcImpl(){
//没必要写
}
static{// 静态块,保证驱动只注册一次。
try {
Class.forName("com.mysql.jdbc.Driver") ;
conn = DriverManager.getConnection(url, user, password) ;
} catch (Exception e) {
throw new DaoException(e.getMessage(),e); //抛出运行时异常
}
}
@Override
public void addUser(User user) {
String sql = "insert into users(uid,upassword,uname,uscore) values(?,?,?,?)" ;
try{
ps = conn.prepareStatement(sql) ;
ps.setInt(1, user.getId()) ;
ps.setString(2, user.getPassword()) ;
ps.setString(3, user.getName()) ;
ps.setFloat(4, user.getScore()) ;
ps.executeUpdate() ;
}catch(Exception e){
throw new DaoException(e.getMessage(),e); //抛出运行时异常
}finally{
//
}
}
@Override
public User load(int id, String password) {
String sql = "select uid,upassword,uname,uscore from users where uid=? and upassword=?" ;
User user = new User() ;
try{
ps = conn.prepareStatement(sql) ;
ps.setInt(1, id) ;
ps.setString(2, password) ;
rs = ps.executeQuery() ;
while(rs.next()){
user.setId(rs.getInt("uid")) ;
user.setPassword(rs.getString("upassword")) ;
user.setName(rs.getString("uname")) ;
user.setScore(rs.getFloat("uscore")) ;
}
return user;
}catch(Exception e){
throw new DaoException(e.getMessage(),e) ; //抛出运行时异常
}finally{
//
}
}
@Override
public User findById(int id) {
String sql = "select uid,upassword,uname,uscore from users where uid=?" ;
User user = new User() ;
try{
ps = conn.prepareStatement(sql) ;
ps.setInt(1, id) ;
rs = ps.executeQuery() ;
while(rs.next()){
user.setId(rs.getInt("uid")) ;
user.setPassword(rs.getString("upassword")) ;
user.setName(rs.getString("uname")) ;
user.setScore(rs.getFloat("uscore")) ;
}
return user;
}catch(Exception e){
throw new DaoException(e.getMessage(),e) ; //抛出运行时异常
}finally{
//
}
}
@Override
public void update(User user) {
String sql = "update users set upassword=?,uname=?,uscore=? where uid = ?" ;
try{
ps = conn.prepareStatement(sql) ;
ps.setString(1, user.getPassword()) ;
ps.setString(2, user.getName()) ;
ps.setFloat(3, user.getScore()) ;
ps.setInt(4, user.getId()) ;
ps.executeUpdate() ;
}catch(Exception e){
throw new DaoException(e.getMessage(),e) ; //抛出运行时异常
}finally{
//
}
}
@Override
public void delete(int id) {
String sql = "delete from users where uid=?" ;
try{
ps = conn.prepareStatement(sql) ;
ps.setInt(1, id) ;
ps.executeUpdate() ;
}catch(Exception e){
throw new DaoException(e.getMessage(),e) ; //抛出运行时异常
}finally{
//
}
}
public void free() {//一个非常严谨的资源释放做法。
try{
if(rs != null)
try{
rs.close();
}catch(SQLException e) {
e.printStackTrace();
}
}finally{
try{
if(ps != null)
try{
ps.close();
}catch(SQLException e) {
e.printStackTrace();
}
}finally{
if(conn != null)
try{
conn.close() ;
}catch(SQLException e) {
e.printStackTrace();
}
}
}
}
}
用于产生数据库访问对象的工厂:DaoFactory类
这个类用于产生具体的数据库操作对象,用于操作数据库,次类我们一般采用单例模式来实现,并且在定义instance的时候就要实例化它,这里我们一般不采用延时加载的做法,因为延时加载只会让我们考虑更多,比如多线程。而这里我们不需要考虑那么多,我们要的就仅仅是产生一个实例而已。
//用单例模式来实现用于产生数据库访问对象的工厂
public class DaoFactory {
private static UserDao dao = null ;
private static DaoFactory instance = new DaoFactory() ;//在定义的时候就实例化
private DaoFactory(){//私有构造方法,只能自己调用
dao = new UserDaoJdbcImpl() ;
}
public static DaoFactory getInstance(){
return instance ;
}
public UserDao getUserDao(){
return dao ;
}
}
用于处理异常的类:DaoException类
继承自RuntimeException类,这个类主要用于处理在数据库操作时产生的异常,是运行时异常。在这里之所以不用编译时异常,其目的就是让业务逻辑层在调用数据访问层时,可以随意地去处理异常,在业务逻辑层是可处理可不处理的,所有上层可根据实际情况去处理异常。
//运行时异常,方便! 跟编译时异常比起来更灵活。
public class DaoException extends RuntimeException {
private static final long serialVersionUID = 1L;
public DaoException() {
}
public DaoException(String message) {
super(message);
}
public DaoException(Throwable cause) {
super(cause);
}
public DaoException(String message, Throwable cause) {
super(message, cause);
}
}
在以后的应用中,对用UserDao的实现不仅仅是UserDaoJdbcImpl,还可能是UserDaoFileImpl或UserDaoSqlImpl等等,要生成具体的数据库访问对象,我们只需要去改工厂就可以了。我写的这个工厂,是属于简单的,如果要写的复杂一点的话,可以将这些接口与具体实现的类,存放在一个.properties文件中,在.properties文件中,是以键值对的形式存放。在工厂里面去访问这个文件,更具提供的键去获得相应的值,这个值就是某个实现类文件的路径,我们通过反射机制就可以获得这个文件的实例化对象,返回到调用工厂处。
另外,我们也不一定要使用工厂,我们也可以使用代理模式,同样也是通过对象组合,在代理里面组合一个UserDao对象,并且这个代理还要继承UserDao,在继承自父类的方法中去调用具体的实现。
相比之下,我认为使用工厂模式是最灵活,也是最好的,毕竟,工厂模式的宗旨就是产生一个实例化对象!这正是我们想要的!