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');

Java层与层之间怎么调用 java中dao层怎么写_sql

然后假设实体类 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:

  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           Constructor for QueryRunner which takes a DataSource. DataSource对象是数据库连接池对象。
将dataSource传递进去,这样update或query方法内部就调用this.getConnection方法来从这个数据源获得连接

queryRunner.update( sql,params);

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

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

 

 

 

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

 int

update(Connection conn, String           Execute an SQL INSERT, UPDATE, or DELETE query without replacement parameters.

 int

update(Connection conn, String sql, Object... params)           Execute an SQL INSERT, UPDATE, or DELETE query.

 int

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

 int

update(String           Executes the given INSERT, UPDATE, or DELETE SQL statement without any replacement parameters.

 int

update(String sql, Object... params)           Executes the given INSERT, UPDATE, or DELETE SQL statement.

 int

update(String sql, Object           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方法

query(Connection conn, String sql, Object[] params, ResultSetHandler<T> rsh)           Deprecated. Use query(Connection,String,ResultSetHandler,Object...) instead

query(Connection conn, String sql, Object param, ResultSetHandler<T> rsh)           Deprecated. Use query(Connection, String, ResultSetHandler, Object...)

query(Connection conn, String sql, ResultSetHandler<T> rsh)           Execute an SQL SELECT query without any replacement parameters.

query(Connection conn, String sql, ResultSetHandler<T> rsh, Object... params)           Execute an SQL SELECT query with replacement parameters.

query(String sql, Object[] params, ResultSetHandler<T> rsh)           Deprecated. Use query(String, ResultSetHandler, Object...)

query(String sql, Object param, ResultSetHandler<T> rsh)           Deprecated. Use query(String, ResultSetHandler, Object...)

query(String sql, ResultSetHandler<T> rsh)           Executes the given SELECT SQL without any replacement parameters.

query(String sql, ResultSetHandler<T> rsh, Object... params)           Executes the given SELECT SQL query and returns a result object.

<T> T

列出几种查询写法:这里就需要用到实体类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>

Java层与层之间怎么调用 java中dao层怎么写_sql_02

再需要一个对应实体类的映射文件,在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();