通过Mybatis实现对单表的增删改查-通过定义一个接口实现

Pom.xml文件 定义工程项目依赖的软件库

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.vincent</groupId>
  <artifactId>mybatisweb</artifactId>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>
  <name>mybatisweb Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.10</version>
      <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.4.4</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.42</version>
    </dependency>

  </dependencies>
  <build>
  <!-- 将mybatisweb项目打包成mybatisweb.war自动部署到tomcat服务器的webapps目录下面 -->
    <finalName>mybatisweb</finalName>
    <plugins>
        <plugin>
            <!-- 使用 cargo自动化部署 -->
            <groupId>org.codehaus.cargo</groupId>
            <artifactId>cargo-maven2-plugin</artifactId>
            <version>1.4.12</version> <!-- 不能用1.3.2 不然用maven编译不成功 -->
            <configuration>
                <container>
                    <!-- 指明使用的tomcat服务器版本 -->
                    <containerId>tomcat8x</containerId>
                     <!--指明tomcat服务器的安装目录 -->
                    <home>C:\fastDev\Tomcat\apache-tomcat-8.5.14</home>                 
                </container>
              <configuration>
                <type>existing</type>
                 <!--指明tomcat服务器的安装目录 -->
                <home>C:\fastDev\Tomcat\apache-tomcat-8.5.14</home>
                <properties><cargo.servlet.port>9090</cargo.servlet.port></properties>
              </configuration>            
            </configuration>
            <executions>
                <execution>
                    <id>cargo-run</id>
                    <phase>install</phase>
                    <goals>
                        <goal>run</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
  </build>
</project>

src/main/resources目录下放置了mybatis的所有配置文件该目录下文件可以直接被java代码引用

为了管理,在src/main/resources目录下新建mybatis目录管理所有mybatis相关的配置信息。

mybatis配置数据源信息

MybatisConfig.xml 在src/main/resources/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">
<configuration>
    <!-- 给类设置别名, 在mapper文件中可以使用这个别名,就不用使用那么长的类名了。 -->
    <typeAliases>
        <typeAlias type="org.vincent.model.Student"
        alias="Student"/>
    </typeAliases>
    <environments default="development">
        <environment id="development">
            <!--  事务管理 -->
            <transactionManager type="JDBC" />
            <!-- 配置数据库连接信息 ,没有用数据库连接池-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url" value="jdbc:mysql://localhost:3306/javaee" />
                <property name="username" value="root" />
                <property name="password" value="1557862201" />
            </dataSource>
        </environment>

    </environments>  
    <mappers>
     <!-- 注册SQL映射信息文件,Mapper.xml文件,   Mapper.xml位于src/main/resources/mybatis这个包下,因为src/main/resources/为classpath,所以resource写成mybatis/mappers/Student.xml-->
        <mapper resource="mybatis/mappers/Student.xml"/>
    </mappers>
</configuration>

设置项目中POJO类和数据库表的映射关系

Student.xml

<?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">
<!-- 为这个mapper指定一个唯一的namespace,namespace的值习惯上设置成包名+sql映射文件名,这样就能够保证namespace的值是唯一的
例如namespace="org.vincent.mapping.Mapper"就是org.vincent.mapping(包名)+Mapper(Mapper.xml文件去除后缀);
但是如有需要通过定义一个接口方法定义访问数据库接口方法,那么namespace必须取接口全类名。
 -->
<mapper namespace="org.vincent.model.IStudentOperation">
    <!-- 在select标签中编写查询的SQL语句, 设置select标签的id属性为getStudent,id属性值必须是唯一的,不能够重复;
    使用parameterType属性指明查询时传递进来使用的参数类型,resultType属性指明查询返回的结果集类型
    resultType="org.vincent.domain.Student"就表示将查询结果映射成一个Student类的对象返回
    Student类就是student表所对应的实体类
    -->
    <!-- 
        根据id查询得到一个student对象
        org.vincent.model.IStudentOperation.getStudentbyId
        id 设置成接口的对应方法名public Student getStudentbyId(int id);
        MyBatis会根据结果自动创建一个ResultMap对象,然后基于查找出来的属性名进行键值对封装,
         然后再看到返回类型是Student对象,再从ResultMap中取出与Student对象匹配的属性名对应的
         键值对进行赋值。
        resultType 是
     -->
    <select id="getStudentbyId" parameterType="int" 
        resultType="Student"> <!-- 直接使用在Mybatis配置文件中定义的类别名 -->
        select * from student where id=#{id}
    </select>

     <!-- 根据一个id 获取一组记录 -->
    <select id="getStudents" parameterType="int"
        resultMap="list">
            select * from student where id >#{id}
     </select>
     <!-- Student是设置别名后 的类型;resultMap是为了返回list类型而设置的。被上面的select引用 
            column 为从数据库查询过来的属性,property属性制定了将从数据库查询过来的属性赋值给对象那个属性。
     -->
     <resultMap type="Student" id="list">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="age" property="age"/>
        <result column="address" property="address"/>
     </resultMap>

     <!-- 插入一条记录 ,
     id和parameterType  分别与IUserOperation接口中的insertStudent方法的名字和  
       参数类型一致。以#{name}的形式引用Student参数的name属性,MyBatis将使用反射读取Student参数  
       的此属性。#{name}中name大小写敏感。引用其他的gender等属性与此一致。useGeneratedKeys设置  
       为"true"表明要MyBatis获取由数据库自动生成的主键id;keyProperty="id"指定将获取到的主键值注入  
       到Student的id属性
     -->
     <insert id="insertStudent" parameterType="Student" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO student(name, age, address) VALUES(#{name}, #{age} ,#{address} )
     </insert>
     <!-- 更新一条记录 -->
     <update id="updateStudent" parameterType="Student" >
        update student SET name=#{name} , address=#{address} ,age=#{age} where id=#{id}
     </update>

     <delete id="deleteStudent" parameterType="int">
        delete from student where id =#{id}
     </delete>

</mapper>

POJO 类

package org.vincent.model;

/**
 * 数据库表对应的Java类;POJO对象
 *
 * @ClassName: Student
 * @Description: TODO(这里用一句话描述这个类的作用)
 * @author PengRong
 * @date 2017年6月16日 上午12:35:37
 *
 */
public class Student {
    private int id;
    private String address;
    private String name;
    private int age;

    public int getId() {
        return this.id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getAddress() {
        return this.address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return this.age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student [id=" + this.id + ", address=" + this.address
                + ", name=" + this.name + ", age=" + this.age + "]";
    }

}

接口类

package org.vincent.model;

import java.util.List;

/**
 * 只有接口没有实现类,用于Mybatis中查询结果 这里的接口方法名必须和Student.xml中select中id属性一致;
 * 比如getStudentbyId 必须和<select id="getStudentbyId" parameterType="int"
 * resultType="Student">一致。 不然测试时候报错说不能绑定异常:
 * org.apache.ibatis.binding.BindingException: Invalid bound statement (not
 * found): org.vincent.model.IStudentOperation.getStudent at
 * org.apache.ibatis.binding
 * .MapperMethod$SqlCommand.<init>(MapperMethod.java:225) at
 * org.apache.ibatis.binding.MapperMethod.<init>(MapperMethod.java:48) at
 * org.apache.ibatis.binding.MapperProxy.cachedMapperMethod(MapperProxy.java:65)
 * at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:58) at
 * com.sun.proxy.$Proxy2.getStudent(Unknown Source) at
 * org.vincent.mybatisweb.StudentTest.testMutiStudent(StudentTest.java:69) at
 * sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at
 * sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
 * at sun.reflect.DelegatingMethodAccessorImpl.invoke(
 * DelegatingMethodAccessorImpl.java:43) at
 * java.lang.reflect.Method.invoke(Method.java:498) at
 * org.junit.runners.model.FrameworkMethod$1
 * .runReflectiveCall(FrameworkMethod.java:45) at
 * org.junit.internal.runners.model
 * .ReflectiveCallable.run(ReflectiveCallable.java:15) at
 * org.junit.runners.model
 * .FrameworkMethod.invokeExplosively(FrameworkMethod.java:42) at
 * org.junit.internal
 * .runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at
 * org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263) at
 * org.junit.runners
 * .BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68) at
 * org.junit.
 * runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47) at
 * org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) at
 * org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) at
 * org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229) at
 * org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) at
 * org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) at
 * org.junit.runners.ParentRunner.run(ParentRunner.java:300) at
 * org.eclipse.jdt.internal
 * .junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) at
 * org.eclipse
 * .jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at
 * org.eclipse
 * .jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner
 * .java:467) at
 * org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(
 * RemoteTestRunner.java:683) at
 * org.eclipse.jdt.internal.junit.runner.RemoteTestRunner
 * .run(RemoteTestRunner.java:390) at
 * org.eclipse.jdt.internal.junit.runner.RemoteTestRunner
 * .main(RemoteTestRunner.java:197)
 *
 *
 *
 * @ClassName: IStudentOperation
 * @Description: TODO(这里用一句话描述这个类的作用)
 * @author PengRong
 * @date 2017年5月16日 上午11:51:04
 *
 */

public interface IStudentOperation {
    // 查询一个数
    public Student getStudentbyId(int id);

    // 查询一列数据
    public List<Student> getStudents(int id);

    // 插入一条记录
    public void insertStudent(Student student);

    // 更新一条记录
    public void updateStudent(Student student);

    // 删除一条记录
    public void deleteStudent(int id);
}


BaseDao

package org.vincent.dao;

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.SqlSessionFactoryBuilder;
import org.apache.log4j.Logger;

public interface BaseDao {
    // 公共的日志记录器和配置文件配置在接口中。
    public Logger logger = Logger.getLogger(BaseDao.class);
    public String MybatisConfig = "mybatis/MybatisConfig.xml";

    // 打开一个Session
    default public SqlSession getSession() throws IOException {
        InputStream inputStream = null;
        inputStream = Resources.getResourceAsStream(BaseDao.MybatisConfig);
        return new SqlSessionFactoryBuilder().build(inputStream).openSession();
    }

    // 关闭一个Session
    default public void closeSession(SqlSession session) {
        if (session != null) {
            session.close();
        }
    }

    // 获取一个日志记录器
    default public Logger getLogger() {
        return BaseDao.logger;
    }

}

Student Dao层

package org.vincent.dao;

import java.io.IOException;
import java.util.List;
import java.util.Objects;

import org.apache.ibatis.session.SqlSession;
import org.vincent.model.IStudentOperation;
import org.vincent.model.Student;

import com.mysql.jdbc.StringUtils;

/**
 * Student 表的单表增删改查实现,基于接口
 *
 * @ClassName: StudentInterfaceDaoImpl
 * @Description: TODO(这里用一句话描述这个类的作用)
 * @author PengRong
 * @date 2017年7月23日 上午11:46:00
 *
 */
public class StudentInterfaceDaoImpl implements BaseDao, IStudentOperation {
    private SqlSession session = null;

    public StudentInterfaceDaoImpl() {
        try {
            this.session = this.getSession();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }// 获取到sqlSession
    }

    /**
     * 关闭Session
     * 
     * @Title: closeSession
     * @Description: TODO(这里用一句话描述这个方法的作用)
     * @param 设定文件
     * @return void 返回类型
     * @throws
     */
    public void closeSession() {
        this.closeSession(this.session);
    }

    // 通关id和匹配到Student.xml中对应的select标签执行单表查询;没用通关Mapper接口
    public Student queryBySql(String sql, int id) {
        Student result = null;
        if (!StringUtils.isNullOrEmpty(sql)) {
            result = this.session.selectOne(sql, id);
        } else {
            result = null;
        }
        return result;
    }

    /**
     * 通过一条记录的id根据IStudentOperation接口方法映射到sql mapper文件中一个select标签;获取到一条记录,
     */
    @Override
    public Student getStudentbyId(int id) {
        // TODO Auto-generated method stub
        IStudentOperation operation = this.session
                .getMapper(IStudentOperation.class);
        Student student = operation.getStudentbyId(id);
        BaseDao.logger.debug(student);
        return student;
    }

    // 获取到大于指定id的所有记录
    @Override
    public List<Student> getStudents(int id) {
        // TODO Auto-generated method stub
        IStudentOperation operation = this.session
                .getMapper(IStudentOperation.class);
        // ② 通过接口方法获取一组数据库记录
        List<Student> list = operation.getStudents(id);
        return list;
    }

    /**
     * 根据一个实例student,将对象插入到数据库中。
     */
    @Override
    public void insertStudent(Student student) {
        // TODO Auto-generated method stub
        IStudentOperation operation = this.session
                .getMapper(IStudentOperation.class);
        if (Objects.nonNull(student)) {
            operation.insertStudent(student);
        } else {
            //
        }
    }

    /**
     * 更新一条记录的相关属性。
     */
    @Override
    public void updateStudent(Student student) {
        // TODO Auto-generated method stub
        IStudentOperation operation = this.session
                .getMapper(IStudentOperation.class);
        operation.updateStudent(student);
    }

    /**
     * 删除一条数据记录
     */
    @Override
    public void deleteStudent(int id) {
        // TODO Auto-generated method stub
        IStudentOperation operation = this.session
                .getMapper(IStudentOperation.class);
        operation.deleteStudent(id);
    }
}

单表增删改查测试类

package org.vincent.mybatisweb;

import java.io.IOException;
import java.util.List;

import org.junit.Test;
import org.vincent.dao.StudentInterfaceDaoImpl;
import org.vincent.model.Student;

/*
 * ORM Mybatis 数据库单表  增 删  改 查操作的单元测试
 * @ClassName: StudentTest
 * @Description: TODO(这里用一句话描述这个类的作用)
 * @author PengRong
 * @date 2017年6月16日 上午1:10:46
 *
 */
public class StudentSingleTableTest {
    /**
     * 根据一个sqlStatement获取到一条记录;使用selcetOne 函数,通过
     * sqlStatement字符串直接映射为Student中对应的SQL语句去执行查询。
     *
     * @Title: test
     * @Description: TODO(这里用一句话描述这个方法的作用)
     * @param @throws IOException 设定文件
     * @return void 返回类型
     * @throws
     */
    @Test
    public void test() throws IOException {
        // sqlStatement是根据Student.xml 这个mapper映射文件中namespace+ select
        // 的id=getStudentbyId 唯一确定的sql字符串
        String sqlStatement = "org.vincent.model.IStudentOperation.getStudentbyId";
        StudentInterfaceDaoImpl studentInterfaceDaoImpl = new StudentInterfaceDaoImpl();
        System.out.println((studentInterfaceDaoImpl
                .queryBySql(sqlStatement, 61)));
        studentInterfaceDaoImpl.closeSession();
    }

    // 通过Id获取一条记录
    @Test
    public void getStudentbyIdTest() {
        StudentInterfaceDaoImpl studentInterfaceDaoImpl = new StudentInterfaceDaoImpl();
        // ① 通过接口方法,查询一条数据库 记录。
        studentInterfaceDaoImpl.getStudentbyId(2);
        studentInterfaceDaoImpl.closeSession();
    }

    /**
     * 用接口的方式编程。这种方式,要注意的一个地方就是。在Student.xml 的映射配置文件中。 mapper节点的
     * namespace="org.vincent.model.IStudentOperation" ,
     * 命名空间非常重要,不能有错,必须与我们定义的接口全类名一致。如果不一致就会出错,
     *
     * @Title: testMutiStudent
     * @Description: TODO(通过接口方法获取到数据库数据)
     * @param
     * @throws IOException
     * @return void 返回类型
     * @throws
     */
    @Test
    public void getStudentsTest() throws IOException {
        StudentInterfaceDaoImpl impl = new StudentInterfaceDaoImpl();
        List<Student> list = impl.getStudents(20);
        for (Student student : list) {
            System.out.println(student);
        }
        impl.closeSession();
    }

    /**
     * 插入一条数据
     *
     * @Title: insertStudentTest
     * @Description: TODO(这里用一句话描述这个方法的作用)
     * @param @throws IOException 设定文件
     * @return void 返回类型
     * @throws
     */
    @Test
    public void insertStudentTest() throws IOException {
        Student student = new Student();
        student.setAddress("深圳市罗湖区红岭北");
        student.setAge(27);
        student.setName("XX00");
        StudentInterfaceDaoImpl impl = new StudentInterfaceDaoImpl();
        impl.insertStudent(student);
        System.out.println(student);// 能获取到数据库生成得id
        impl.closeSession();
    }

    /**
     * 通过id查询一条记录对应的对象,然后更改记录对象,最后通过接口方法更新一条记录
     *
     * @Title: updateStudent
     * @Description: TODO(这里用一句话描述这个方法的作用)
     * @param
     * @throws IOException
     * @return void 返回类型
     * @throws
     */
    @Test
    public void updateStudent() throws IOException {
        StudentInterfaceDaoImpl impl = new StudentInterfaceDaoImpl();
        Student student = impl.getStudentbyId(60);
        student.setAddress("东莞市长安街");
        impl.updateStudent(student);
        impl.closeSession();
    }

    /**
     * 通过数据库id, 删除一条记录。
     *
     * @Title: deleteStudent
     * @Description: TODO
     * @param @throws IOException 设定文件
     * @return void 返回类型
     * @throws
     */
    @Test
    public void deleteStudent() throws IOException {
        StudentInterfaceDaoImpl dao = new StudentInterfaceDaoImpl();
        dao.deleteStudent(59);
        dao.closeSession();
    }
}

猜你喜欢

转载自blog.csdn.net/jq_ak47/article/details/75949121