Mydatis对数据库的增删改查
MyBatis工作原理
读取 MyBatis 配置文件 mybatis-config.xmlo mybatis-config.xml 作为 MyBatis 的全局配 置文件,配置了 MyBatis 的运行环境等信息,其中主要内容是获取数据库连接。
加载映射文件 Mapper.xmlo Mapper.xml 文件即 SOL 映射文件,该文件中配置了操作 数据库的 SOL 语句,需要在 mybatis-config.xml 中加载才能执行。 mybatis-config.xml 可以加 载多个配置文件,每个配置文件对应数据库中的一张表。
构建会话工厂。 通过 MyBatis 的环境等配置信息构建会话工厂 SqlSessionFactory。
创建 SqlSession 对象。 由会话工厂创建 SqlSession 对象,该对象中包含了执行 SOL 的所有方法。
MyBatis 底层定义了一个 Executor 接口来操作数据库,它会根据 SqlSession 传递的参 数动态地生成需要执行的 SOL 语句,同时负责查询缓存的维护。
在 Executor 接口的执行方法中,包含一个 MappedStatement 类型的参数, 该参数是对映射信息的封装 ,用于存储要映射的 SOL 语句的 id、参数等。 Mapper.xml 文件中一个 SOL 对应一个. MappedStatement 对象 , SOL 的 id 即是 MappedStatement 的 id。
7.输入参数映射。 在执行方法时, MappedStatement 对象会对用户执行 SOL 语句的输入 参数进行定义(可以定义为 Map、List 类型、基本类型和 POJO 类型 ), Executor 执行器会通过 MappedStatement 对象在执行 SOL 前,将输入的 Java 对象映射到 SOL 语句中 。 这里对输入参 数的映射过程就类似于 JDBC 编程中对 preparedStatement 对象设置参数的过程。
输出结果映射。 在数据库中执行完 SOL 语句后, MappedStatement 对象会对 SOL 执 行输出的结果进行定义(可以定义为 Map 和List 类型、基本类型、 POJO 类型 ), Executor 执行 器会通过 MappedStatement 对象在执行 SOL 语句后,将输出结果映射至 Java 对象中。 这种将 输出结果映射到 Java 对象的过程就类似于 JDBC 编程中对结果的解析处理过程。
通过上面对 MyBatis 框架执行流程的讲解,相信读者对 MyBatis 框架已经有了一个初步的了 解。 对于初学者来说,上面所讲解的内容可能不会完全理解,现阶段也不要求读者能完全理解, 这里讲解 MyBatis 框架的执行过程是为了方便后面程序的学习。 在学习完 MyBatis 框架后,读者 自然就会明白上面所讲解的内容了 。
SqlSessionFactory
SqlSessionFactory 是 MyBatis 框架中十分重要的对象,它是单个数据库映射关系经过编译 后的内存镜像,其主要作用是创建 SqlSession。
SqlSessionFactory 对象的实例可以过SqlSessionFactoryBuilder 对象来构建,而 SqlSessionFactoryBuilder 则可以通过 XML 配置文件 或一个预先定义好的 Configuratiori 实例构建出 SqlSessionFactory 的实例。
Sq ISessionFactory 对象是线程安全的,它一旦被创建,在整个应用执行期间都会存在。 如果我 们多次地创建同一个数据库的 SqlSessionFactory,那么此数据库的资源将很容易被耗尽。 为了解决 此问题,通常每一个数据库都会只对应一个 SqlSessionFactory,所以在构建 SqlSessionFactory 实例时,建议使用单列模式。
SqlSession
SqlSession 是 MyBatis 框架中另一个重要的对象,它是应用程序与持久层之间执行交互操 作的一个单线程对象,其主要作用是执行持久化操作。 SqlSession 对象包含了数据库中所有执 行 SQL 操作的方法,由于其底层封装了 JDBC 连接,所以可以直接使用其实例来执行己映射的 SQL 语句。
每一个线程都应该有一个自己的 SqlSession 实例,并且该实例是不能被共享的。 同时, SqlSession 实例也是线程不安全的,因此其使用范围最好在一次请求或一个方法中,绝不能将其放 在一个类的静态字段、实例字段或任何类型的管理范围(如 Servlet 的 HttpSession )中使用。 使用 完 SqlSession 对象之后,要及时地关闭它,通常可以将其放在 finally 块中关闭。
SqlSession 对象中包含了很多方法,其常用方法如下所示。
• T selectOne ( String statement ); 查询方法。 参数 statement 是在配置文件中定义的元素的 id。 使用该方法后,会返 回执行 SOL 语句查询结果的一条泛型对象。
• T selectOne ( String statement, Object parameter ); 查询方法。 参数 statement 是在配置文件中定义的<selecb元素的 id , parameter 是查询所 需的参数。 使用该方法后,会返回执行 SOL 语句查询结果的一条泛型对象。
• List selectList ( String statement ); 查询方法。 参数 statement 是在配置文件中定义的元素的 id。 使用该方法后,会返 回执行 SOL 语句查询结果的泛型对象的集合。
• List selectList ( String statement, Object parameter ); 查询方法。 参数 statement 是在配置文件中定义的<selecb元素的 id , parameter 是查询所 需的参数。 使用该方法后,会返回执行 SOL 语句查询结果的泛型对象的集合。
• List selectList ( String statement, Object parameter, RowBounds rowBounds ); 查询方法。 参数 statement 是在配置文件中定义的元素的 id , parameter 是查询所 需的参数, rowBounds 是用于分页的参数对象。 使用该方法后,会返回执行 SOL 语句查询结果 的泛型对象的集合。
• void select ( String statement, Object parameter, ResultHandler handler ); 查询方法。 参数 statement 是在配置文件中定义的<selecb元素的 id , parameter 是查询所 需的参数, ResultHandler 对象用于处理查询返回的复杂结果集,通常用于多表查询。
• int insert ( String statement ); 插入方法。 参数 statement 是在配置文件中定义的<inserb元素的 id。 使用该方法后,会返 回执行 SOL 语句所影响的行数。
• int insert ( String statement, Object parameter ); 插入方法。 参数 statement 是在配置文件中定义的<inserb元素的 id , parameter 是插入所 需的参数。 使用该方法后,会返回执行 SOL 语句所影响的行数。
• int update ( String statement ); 更新方法。 参数 statement 是在配置文件中定义的元素的 id。 使用该方法后,会 返回执行 SOL 语句所影响的行数。
• int update ( String statement, Object parameter ); 更新方法。 参数 statement 是在配置文件中定义的元素的 id , parameter 是更新 所需的参数。 使用该方法后,会返回执行 SOL 语句所影响的行数。
• int delete ( String statement ); 删除方法。 参数 statement 是在配置文件中定义的元素的 id。 使用该方法后,会返 回执行 SOL 语句所影响的行数。
• int delete ( String statement, Object parameter ); 删除方法。 参数 statement 是在配置文件中定义的元素的 id , parameter 是删除所 需的参数。 使用该方法后,会返回执行 SOL 语句所影响的行数。
配置mybatis_conf.xml文件
<configuration>
<!-- 引入外部的properties文件,只能引入一个 -->
<properties resource="jdbc.properties" />
<settings>
<setting name="mapUnderscoreToCamelCase" value="false"/>
</settings>
<!-- 定义类型别名(全局),在所有的Mapper.xml中都可以用 -->
<typeAliases>
<typeAlias type="com.lanou3g.mybatis.bean.Teacher" alias="Teacher" />
<typeAlias type="com.lanou3g.mybatis.bean.Student" alias="Student" />
</typeAliases>
<!-- 配置多套环境的数据库连接参数(如:开发环境、生产环境) -->
<environments default="zhangguosheng">
<environment id="zhangguosheng">
<!-- 事务管理器:
MANAGED: 这个配置就是告诉mybatis不要干预事务,具体行为依赖于容器本身的事务处理逻辑。
JDBC: 这个配置就是直接使用了 JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务作用域。
-->
<transactionManager type="MANAGED"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
<environment id="zhangguosheng">
<transactionManager type="MANAGED"/>
<dataSource type="POOLED">
<property name="driver" value="${zhangguosheng.jdbc.driver}"/>
<property name="url" value="${zhangguosheng.jdbc.url}"/>
<property name="username" value="${zhangguosheng.jdbc.user}"/>
<property name="password" value="${zhangguosheng.jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!-- 将mapper SQL映射文件包含进来 -->
<mappers>
<mapper class="com.lanou3g.mybatis.dao.StudentDao" />
<mapper resource="mapper/TeacherMapper.xml" />
<mapper resource="mapper/StudentMapper.xml" />
<mapper class="com.lanou3g.mybatis.dao.CourseDao" />
</mappers>
</configuration>
配置properties
jdbc.url=jdbc:mysql://localhost:3306/ZGS?characterEncoding=utf8
jdbc.driver=com.mysql.jdbc.Driver
jdbc.user=root
jdbc.password=zxcvbnm.
zhangguosheng.jdbc.url=jdbc:mysql://localhost:3306/ZGS?characterEncoding=utf8
ZGS.jdbc.driver=com.mysql.jdbc.Driver
ZGS.jdbc.user=root
ZGS.jdbc.password=zxcvbnm.
以xml方式为例进行数据库操作
建立一个接口如Teacher接口:
public interface TeacherDao {
List<Teacher> queryAll();
/**
* 多参数查询
* @param id
* @param age
* @return
*/
// List<Teacher> queryByIdAndAge(@Param("TID") int id, @Param("Tage") int age);
int insertTeacher(Teacher teacher);
int insertTeacherByParam(@Param("Tname") String tname, @Param("Tage") int age);
/* Teacher queryById(int id);
Teacher queryByAge(int age);*/
int updateTeacherById(Teacher teacher);
int deleteTeacherById(int id);
}
建一个对应的Teacher实体类:
@Getter
@Setter
public class Student {
private String sname;
private String ssex;
public Student() {}
public Student(String sname, String ssex) {
this.sname = sname;
this.ssex = ssex;
}
@Override
public String toString() {
return "{" +
"sname='" + sname + '\'' +
", sex='" + ssex + '\'' +
"}\n";
}
}
创建一个Mapper—TeacherMapper.xml
<mapper namespace="com.lanou3g.mybatis.dao.TeacherDao">
<resultMap id="teacher" type="Teacher">
<result property="id" column="TID" />
<result property="age" column="Tage" />
<result property="tname" column="Tname" />
</resultMap>
<!-- 此处的id是查询语句的名称,对应接口中的方法名 -->
<select id="queryAll" resultMap="teacher">
select * from teacher;
</select>
<!-- 带一个简单类型的参数, 这种情况下parameterType属性可以省略,mybatis可以自动推断出类型 -->
<!-- <select id="queryById" parameterType="int" resultMap="teacher">
select * from teacher where TID = #{id};
</select>
<select id="queryByAge" parameterType="int" resultMap="teacher">
select *from teacher where Tage = #{age};
</select>-->
<!-- 带两个参数,需要在接口中通过@Param注解指定名称(因为编译时参数名不会保留) -->
<!-- <select id="queryByIdAndAge" resultMap="teacher">
select * from teacher where TID = #{TID} and Tage <= #{Tage};
</select>-->
<!-- insert、update、delete的返回值都是int(影响行数) -->
<!-- 自定义类型参数,通过#{属性名}可以直接获取引入类型参数的属性值 -->
<insert id="insertTeacher" parameterType="Teacher" >
insert into teacher(Tname) values (#{tname});
</insert>
<insert id="insertTeacherByParam">
insert into teacher(Tname, Tage) values (#{Tname}, #{Tage});
</insert>
<update id="updateTeacherById" parameterType="Teacher">
update teacher set Tname = #{tname}, Tage = #{age} where TID = #{id}
</update>
<delete id="deleteTeacherById">
delete from teacher where TID = #{id};
</delete>
</mapper>
在main方法进行测试
@Test
public void testQueryAll() {
//查询教师表
/*TeacherDao teacherDao = MyBatisTools.getInstance().openSession().getMapper(TeacherDao.class);
List<Teacher> teacherList = teacherDao.queryAll();
log.info("teacherList: " + teacherList);*/
}
@Test
public void testInsert() {
// 新增Teacher表
System.out.println("--------------插入前:");
List<Teacher> teacherList = teacherDao.queryAll();
System.out.println(teacherList);
int ret = teacherDao.insertTeacher(new Teacher("铜赛赛"));
log.info("影响的行数: " + ret);
// 比较low的写法(不推荐)
/*int ret = teacherDao.insertTeacherByParam("哈哈嗝", 99);
log.info("影响的行数: " + ret);*/
System.out.println("--------------插入后:");
teacherList = teacherDao.queryAll();
System.out.println(teacherList);
}
/*@Test
public void testQueryById() {
Teacher teacher = teacherDao.queryById(6);
System.out.println(teacher);
}
@Test
public void testQueryByAge() {
Teacher teacher = teacherDao.queryByAge(24);
System.out.println(teacher);
}*/
/**
* 多个参数查询语句
*/
/*@Test
public void testQueryByIdAndAge() {
List<Teacher> teacherList = teacherDao.queryByIdAndAge(6, 99);
log.info("查询结果:" + teacherList);
}*/
@Test
public void testUpdate() {
Teacher teacher = new Teacher();
teacher.setId(6);
teacher.setAge(98);
teacher.setTname("托尼托尼乔巴老师");
int rows = teacherDao.updateTeacherById(teacher);
log.info("更新行数:" + rows);
}
@Test
public void testDelete() {
int rows = teacherDao.deleteTeacherById(30);
log.info("删除行数:" + rows);
}
}
测试结果:
![插入新数据]
(https://img-blog.csdnimg.cn/20190625085529777.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1h6bWJ6,size_16,color_FFFFFF,t_70)
![查询数据]
(https://img-blog.csdnimg.cn/20190625085652556.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1h6bWJ6,size_16,color_FFFFFF,t_70)
Mybatis多表查询示例
创建BookMypper接口
package com.lanou3g.mybatis.dao;
import com.lanou3g.mybatis.bean.Book;
import java.util.List;
public interface BookMapper {
List<Book> queryBooks();
}
创建Book实体类
@Getter
@Setter
public class Book {
private Integer id;
private String bname;
private BookType bookType;
private String author;
private String authorGender;
private Integer price;
private String description;
@Override
public String toString() {
return "Book{" +
"id=" + id +
", bname='" + bname + '\'' +
", bookType=" + bookType +
", author='" + author + '\'' +
", authorGender='" + authorGender + '\'' +
", price=" + price +
", description='" + description + '\'' +
"}\n";
}
}
创建BookType实体类
@Setter
@Getter
public class BookType {
private Integer id;
private String tname;
@Override
public String toString() {
return "BookType{" +
"id=" + id +
", tname='" + tname + '\'' +
'}';
}
}
BookMapper.xml
<!-- namespace对应空Dao接口的全名 -->
<mapper namespace="com.lanou3g.mybatis.dao.BookMapper">
<resultMap id="book" type="com.lanou3g.mybatis.bean.Book">
<id column="bid" property="id"/>
<result column="bname" property="bname"/>
<result column="author" property="author"/>
<result column="author_gender" property="authorGender"/>
<result column="price" property="price"/>
<result column="description" property="description"/>
<association property="bookType" javaType="com.lanou3g.mybatis.bean.BookType">
<id column="bt_id" property="id" />
<result column="tname" property="tname" />
</association>
</resultMap>
<select id="queryBooks" resultMap="book">
select b.*,bt.*, b.bid bid, bt.tid bt_id from book b, booktype bt where b.btype = bt.tid;
</select>
</mapper>
不要忘记 将mapper SQL映射文件包含进来
![将mapper SQL映射文件包含进来]
(https://img-blog.csdnimg.cn/20190625215018484.png)
测试
@Test
public void testCascade(){
List<Book> bookList = bookMapper.queryBooks();
log.info("关联查询图书表:"+bookList);
}