DAO层的写法总结

DAO层的写法总结:

本文中进行的总结,主要针对的是持久层,并不需要Web工程的环境,只需要Java工程即可。

DAO层持有实体层的对象,DAO层的增删改查写法会很多。下面总结一下三种写法:这里只给出查询的写法,其他写法类似。

1、最原始的JDBC写法         

2、Apache的 Commons DbUtils

3、Hhibernate 或 Mybatis方式

其中,方式1大家应该都会了,方式2是黑马视频中提过的,我们主要是理解。方式3里的Mybatis在本文中有详细的代码和结构、配置展示。

mysql 5.5 建库、建表、两行示例数据的语句:(账号和密码都是root)

         create database studentdb;
		 use studentdb;
		 
		 create table student(
		 id int primary key auto_increment,
		 name varchar(20),
		 school varchar(20)
		 );
		 
		 insert into student(name,school) values('zhangsan','ningxiashifan');
		 insert into student(name,school) values('lisi','ningxiashifan');

然后假设实体类 User:(虽然JDBC方式跟这没关系。。。但还是先写在这里)

package domain;

public class User {
	
	private int id;
	private String name;
	private String school;
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getSchool() {
		return school;
	}
	public void setSchool(String school) {
		this.school = school;
	}
	public String toString() {
		return "User [id=" + id + ", name=" + name + ", school=" + school + "]";
	}
	public User(int id, String name, String school) {
		super();
		this.id = id;
		this.name = name;
		this.school = school;
	}
}

 

第一种:JDBC写法,需要把数据库表、表的字段写在java代码里

import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;

import com.mysql.jdbc.Connection;
import com.mysql.jdbc.PreparedStatement;

public class JdbcDemo1 {

	public static void main(String[] args) throws SQLException {

		//1、注册驱动
		DriverManager.registerDriver(new com.mysql.jdbc.Driver());

		//2、获取数据库连接
		Connection conn = (Connection) DriverManager.getConnection("jdbc:mysql://localhost:3306/studentdb","root","root");

		//3、获取操作数据库预处理对象
		PreparedStatement pstm = (PreparedStatement) conn.prepareStatement("select * from student");

		//4、执行sql语句
		ResultSet rs = pstm.executeQuery();

		//5、遍历结果集
		while (rs.next() == true) {
			System.out.println(rs.getString("name")+ "," + rs.getString("school"));
		}

		//6、关闭资源
		rs.close();
		pstm.close();
		conn.close();
	}

}

 

第二种:org.apache.commons.dbutils  包

API:https://tool.oschina.net/apidocs/apidoc?api=commons-dbutils

  commons-dbutilsAPI,相关的两个类:

  • org.apache.commons.dbutils.QueryRunner
  • org.apache.commons.dbutils.ResultSetHandler

  一个工具类

  • org.apache.commons.dbutils.DbUtils   全是静态方法

 

common-dbutils.jar包中,QueryRunner 类

对于QueryRunner构造方法的说明(两种构造方法,对事务的支持情况)

1、不带参数的QueryRunner构造方法。需要将来使用时再传入连接,并控制连接关闭。(支持手动事务,建议使用)

构造方法 QueryRunner()   可以不使用连接池
          Constructor for QueryRunner.

这种情况下,调用update或query方法时,需要传入对应的connection参数

queryRunner.update(conn, sql,params);

conn.close();

dbutils调用这种带connection参数的update等方法时,只会关闭preparedstatement和resultset对象,不会关闭conneciton对象,所以适合手动逻辑操纵事务。

但一些情况下,没有手动关闭连接,就可能会导致连接池满了,访问数据库是处于一直等待的状态,这点需要注意。

 

2、带参数的QueryRunner构造方法,构造时即传入连接池对象(比如c3p0连接池),由dbutils自动控制关闭连接,每条SQL语句都是一个事务。

连接池的目的是,每次执行SQL时,从池中获取一个连接,再执行sql,最后再关闭连接。

构造方法 QueryRunner(DataSource ds)   必须使用连接池
          Constructor for QueryRunner which takes a DataSource. DataSource对象是数据库连接池对象。
将dataSource传递进去,这样update或query方法内部就调用this.getConnection方法来从这个数据源获得连接

queryRunner.update( sql,params);

操作完后,就关闭conneciton,preparedstatement和resultset对象.

事务是自动控制的,一条SQL语句一个事务,不需要人为的控制。这种比较简单,但是需要构造时,先获取连接池。

 

 

 

update方法:
  可执行增、删、改语句,返回值代表

 intupdate(Connection conn, String sql)
          Execute an SQL INSERT, UPDATE, or DELETE query without replacement parameters.
 intupdate(Connection conn, String sql, Object... params)
          Execute an SQL INSERT, UPDATE, or DELETE query.
 intupdate(Connection conn, String sql, Object param)
          Execute an SQL INSERT, UPDATE, or DELETE query with a single replacement parameter.  参数1是指定连接对象、参数2是SQL语句、参数3是替换的模板参数;返回值是执行结果所影响的行数。
 intupdate(String sql)
          Executes the given INSERT, UPDATE, or DELETE SQL statement without any replacement parameters.
 intupdate(String sql, Object... params)
          Executes the given INSERT, UPDATE, or DELETE SQL statement.
 intupdate(String sql, Object param)
          Executes the given INSERT, UPDATE, or DELETE SQL statement with a single replacement parameter.

int update(String sql, Object... params) 
  //它使用内部的连接池,每条SQL执行都是一个独立的Connection,不支持事务。

 

int update(Connection con, String sql, Object... parmas) 
需要调用者提供Connection,这说明本方法不再使用池来管理Connection了,而是用指定的一个Connection,
可以在多次操作中,传入同一个Connection,所以只有它支持事务,但也需要自己来创建和维护连接池(如果你使用连接池的话)

 

比如“增”的写法:  void  add();   ,然后,“删”  “改”的写法都差不多。

public void  add()  throws  SQLException {
  Connection conn = (Connection) DriverManager.getConnection("jdbc:mysql://localhost:3306/studentdb","root","root");  //  获取数据库连接
  QueryRunner qr = new QueryRunner();
  String sql = "insert into student values(?,?,?)";
  Object[] params = {3, "wangwu", "ningxiashifan"};
  qr.update(conn,sql, params);  //调用QueryRunner类 update方法的三参数方法
 }

“查”的写法:需要使用QueryRunner类的 query方法

<T> T
query(Connection conn, String sql, Object[] params, ResultSetHandler<T> rsh)
          Deprecated. Use query(Connection,String,ResultSetHandler,Object...) instead
<T> T
query(Connection conn, String sql, Object param, ResultSetHandler<T> rsh)
          Deprecated. Use query(Connection, String, ResultSetHandler, Object...)
<T> T
query(Connection conn, String sql, ResultSetHandler<T> rsh)
          Execute an SQL SELECT query without any replacement parameters.
<T> T
query(Connection conn, String sql, ResultSetHandler<T> rsh, Object... params)
          Execute an SQL SELECT query with replacement parameters.
<T> T
query(String sql, Object[] params, ResultSetHandler<T> rsh)
          Deprecated. Use query(String, ResultSetHandler, Object...)
<T> T
query(String sql, Object param, ResultSetHandler<T> rsh)
          Deprecated. Use query(String, ResultSetHandler, Object...)
<T> T
query(String sql, ResultSetHandler<T> rsh)
          Executes the given SELECT SQL without any replacement parameters.
<T> T
query(String sql, ResultSetHandler<T> rsh, Object... params)
          Executes the given SELECT SQL query and returns a result object.

列出几种查询写法:这里就需要用到实体类User了。

(1)单行结果集用法: 这里把查询到的对象信息打印出来 void  find() ,查询结果是一个实体类的对象(javabean对象)

 public void find() throws SQLException {
 Connection conn = (Connection) DriverManager.getConnection("jdbc:mysql://localhost:3306/studentdb","root","root");  //  获取数据库连接  

 QueryRunner qr = new QueryRunner();

 String sql = "select * from student where id=?";  // 给出sql模板
 
 Object[] params = {3};         // 给出参数,上面模板虽然是一个参数,但这里用的是数组方式
  
  // 接下来执行query()方法,需要给出结果集处理器,即ResultSetHandler的实现类对象
  // 我们用的是org.apache.commons.dbutils.handlers.BeanHandler;它实现了ResultSetHandler;
  // 它需要一个类型,然后它会把rs中的数据封装到指定类型的一个javabean对象中,然后返回。
  User   user  = qr.query(sql, new BeanHandler<User>(User.class), params);
  System.out.println(user);
  conn.close();//别忘了关连接
 }

(2)多行结果集用法: void  findAll()

 /**
  * BeanListHandler的应用,它是多行处理器
  * 每行对象一个User对象!
  * @throws Exception
  */
 @Test
 public void findAll() throws Exception {
Connection conn = (Connection) DriverManager.getConnection("jdbc:mysql://localhost:3306/studentdb","root","root");  //  获取数据库连接

  QueryRunner qr = new QueryRunner();

  String sql = "select * from student";

  List<User> userList = qr.query(sql, new BeanListHandler<User>(User.class));//BeanListHandler类用于查询结果是多行,返回一个List<T>
  
  System.out.println(userList);//或增强型for循环去遍历List
  conn.close();
 }

(3)结果集不仅可以是实体类、实体类的List,还可以是map对象,和List<map<key,value>>;

/**
  * MapHandler的应用,它是单行处理器,把一行转换成一个Map对象
  * @throws SQLException
  */
 @Test
 public void find() throws SQLException  {
Connection conn = (Connection) DriverManager.getConnection("jdbc:mysql://localhost:3306/studentdb","root","root");  //  获取数据库连接

  QueryRunner qr = new QueryRunner();

  String sql = "select * from student where id=?";

  Object[] params = {3};

  Map map = qr.query(sql, new MapHandler(), params);
  
  System.out.println(map);
  conn.close();
 }

 

/**
  * MapListHandler,它是多行处理器,把每行都转换成一个Map,即List<Map>
  * @throws SQLException
  */
 @Test
 public void findAll() throws SQLException  {
Connection conn = (Connection) DriverManager.getConnection("jdbc:mysql://localhost:3306/studentdb","root","root");  //  获取数据库连接
  QueryRunner qr = new QueryRunner();
  String sql = "select * from  student";
  List<Map<String,Object>> mapList = qr.query(sql, new MapListHandler());
  
  System.out.println(mapList); //可以使用增强型for循环遍历List
  conn.close();
 }

(4) 查询的结果集是单行单列的结果,比如select  count(*) 的结果

/**
  * ScalarHandler,它是单行单列时使用,最为合适!
  * @throws SQLException
  */
 @Test
 public void find() throws SQLException {
Connection conn = (Connection) DriverManager.getConnection("jdbc:mysql://localhost:3306/studentdb","root","root");  //  获取数据库连接
  QueryRunner qr = new QueryRunner();
  String sql = "select count(*) from  student";
  /*
   * Integer、Long、BigInteger
   */
  Number cnt = (Number)qr.query(sql, new ScalarHandler());
//不同数据库对于count()函数的返回值类型定义不同,如果更换驱动,比如到了Oracle,可能是BigInteger类型
//mySql是 Long类型,不管是Integer、BigInteger、Long类型,都有共同顶层类Number型。
  
  long c = cnt.longValue();
  System.out.println(c);
  conn.close();
  }
}

第三种:Mybatis用法

基于XML文件.在类路径(eclipse的src路径,或者IDEA的java、resource路径)下,首先需要有一个Mybatis的配置文件。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--  XML 配置文件包含对 MyBatis 系统的核心设置 -->
<configuration>


    <environments default="mysql">
        <!-- 环境配置,即连接的数据库。 -->
        <environment id="mysql">
            <!--  指定事务管理类型,type="JDBC"指直接简单使用了JDBC的提交和回滚设置 -->
            <transactionManager type="JDBC"/>
            <!--  dataSource指数据源配置,POOLED是JDBC连接对象的数据源连接池的实现。 -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/studentdb"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <!-- mappers告诉了MyBatis去哪里找持久化类的映射文件 -->
    <mappers>
        <mapper resource="mapper/UserMapper.xml"/>
    </mappers>
</configuration>

再需要一个对应实体类的映射文件,在mapper包下的 UserMapper.xml ,在上面的基础配置文件里,需要声明出来。

实体类User(POJO),还需要对应的接口mapper.UserMapper,接口的名字与映射文件名相同,这里是接口UserMapper.java

package mapper;

import java.util.List;

import domain.User;

public interface UserMapper {
	
    public User selectUser(int id);     //查到User对象
    public void saveUser(User user);    //增   
    public void updateUser(User user);    //改
    public void deleteUser(int id);       //删
    public List<User> selectAll();       //查到List<User>
}

演示:“查”的写法,在接口中书写方法  User selectUser(int  id);

SQL返回的列名,要与上面的POJO类的属性对应起来,MyBatis会自动对他们做映射。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace指用户自定义的命名空间。 -->
<mapper namespace="mapper.UserMapper">

    <!--"增"
        id="save"是唯一的标示符
        parameterType属性指明插入时使用的参数类型
        useGeneratedKeys="true"表示使用数据库的自动增长策略
     -->
    <insert id="saveUser" parameterType="domain.User" useGeneratedKeys="true">
  	INSERT INTO student(id,name,school)
  	VALUES(#{id},#{name},#{school})
  </insert>


    <!-- "查",查到一个User对象
    parameterType="int"表示该sql语句中的模板参数#{}类型是int
    resultType 表示返回值的类型-->
    <select id="selectUser" parameterType="int"  resultType="domain.User">
        SELECT * FROM student WHERE id = #{id}
    </select>


    
    <!-- "查",查到一个List<User>列表-->
    <select id="selectAll"  resultType="domain.User">
        SELECT * FROM  student
    </select>



    <!-- "改"操作-->
    <update id="updateUser" parameterType="domain.User">
        UPDATE student
        SET id = #{id},   name = #{name},  school = #{school}
        WHERE id = #{id}
    </update>


    <!-- "删"操作 -->
    <delete id="deleteUser" parameterType="int">
        DELETE FROM student WHERE id = #{id}
    </delete>

</mapper>

 

测试查一个User:

package test;
import java.io.IOException;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import domain.User;
import mapper.UserMapper;
public class TestSelect {

	public static void main(String[] args) throws Exception {
		SqlSessionFactory sqlSessionFactory = null;
		String resource = "mybatis-config.xml";
		InputStream is;
		try {
		    is = Resources.getResourceAsStream(resource);
		    sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
		} catch (IOException e) {
		    e.printStackTrace();
		}

		SqlSession  sqlSession = null;
		try{

		sqlSession = sqlSessionFactory.openSession();//打开会话
	        UserMapper mapper = sqlSession.getMapper(UserMapper.class);//获取mapper
	        User user = mapper.selectUser(1); //sql查询逻辑,返回一个User对象
	        System.out.println(user); //看能否能查询到返回值对象
		    sqlSession.commit();//提交事务
		}catch(Exception e){
		    sqlSession.rollback();//回滚事务
		}finally{
		   //打开会话失败时,sqlSession会是null,此时不需要进行关闭
		   if(sqlSession != null)
		        sqlSession.close();
		}
	}
}

//控制台输出:User [id=1, name=zhangsan, school=ningxiashifan]

 

测试删除一个User对象

package test;
//省略了跟上面一样.....
public class TestDelete {

	public static void main(String[] args) throws Exception {
		//...跟上面一样

	        UserMapper mapper = sqlSession.getMapper(UserMapper.class);//获取mapper
		
	        mapper.deleteUser(2);  //SQL删除业务mybatis代码

		sqlSession.commit();//提交事务
                //....跟上面一样
		
	}
}

//进mysql命令查看,确实删除成功。

 

测试增加一个User对象

package test;
//省略。。。跟上面一样
public class TestSave {

	public static void main(String[] args) throws Exception {
	//省略。。。跟上面一样
	        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
	        mapper.saveUser(new User(2, "zhaoliu", "ningxiashifan"));  //mybatis增加User对象业务的代码
		sqlSession.commit();//提交事务
        //省略。。。跟上面一样
		
	}
}


//再次运行TestSelect ,查id=2可以看到控制台:User [id=2, name=zhaoliu, school=ningxiashifan]

 

改动一个User对象测试:

package test;
//省略。。。跟上面一样
public class TestUpdate {

	public static void main(String[] args) throws Exception {
	//省略。。。跟上面一样
                UserMapper mapper = sqlSession.getMapper(UserMapper.class);
	        User user = new User(2, "wangwu", "ningxiashifan");  //创建一个对象,以便用于更新
	        mapper.updateUser(user);//修改一个User对象的mybatis业务代码
		sqlSession.commit();//提交事务
        //省略。。。跟上面一样
		
	}
}


//注意,改动时,不要超过原始mysql的varchar的数据长度。
//再次运行TestSelect ,id=2,控制台看到  User [id=2, name=wangwu, school=ningxiashifan]

 

 

查询全部User对象得到List<User>测试代码:

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = mapper.selectAll();
        for (User user : userList) {
            System.out.println(user);
        }
        sqlSession.commit();

 

  • 5
    点赞
  • 67
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在常见的软件开发中,Service DAO(Data Access Object)是常用的架构次。它们分别负责业务逻辑的处理和数据访问的操作。 Service 通常包含了业务逻辑的实现,它处理业务需求、调用 DAO 完成数据操作,并将结果返回给调用方。在 Service 中,可以包含事务管理、数据校验、业务规则验证等逻辑。 DAO 主要负责数据库的访问和操作,它提供了对数据库的增删改查等基本操作接口。DAO一般包含数据库连接、SQL语句的执行和结果集的处理等功能。 关于两者的具体写法,以下是一种常见的实现方式: DAO 写法示例: ```java public interface UserDao { User getUserById(int id); void createUser(User user); void updateUser(User user); void deleteUser(int id); } public class UserDaoImpl implements UserDao { public User getUserById(int id) { // 数据库查询操作 // 返回查询到的 User 对象 } public void createUser(User user) { // 数据库插入操作 } public void updateUser(User user) { // 数据库更新操作 } public void deleteUser(int id) { // 数据库删除操作 } } ``` Service 写法示例: ```java public interface UserService { User getUserById(int id); void createUser(User user); void updateUser(User user); void deleteUser(int id); } public class UserServiceImpl implements UserService { private UserDao userDao; public User getUserById(int id) { // 可以在这里添加业务逻辑的处理 return userDao.getUserById(id); } public void createUser(User user) { // 可以在这里添加业务逻辑的处理 userDao.createUser(user); } public void updateUser(User user) { // 可以在这里添加业务逻辑的处理 userDao.updateUser(user); } public void deleteUser(int id) { // 可以在这里添加业务逻辑的处理 userDao.deleteUser(id); } } ``` 在实际开发中,通常会使用依赖注入(Dependency Injection)等技术将 DAO 注入到 Service 中,实现解耦和模块化的设计。以上只是一种示例写法,具体实现还需要根据项目的需求和技术栈来确定。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值