MyBatis
MyBatis
像MyBatis、Hibernate都是属于ORM框架。
mybatis框架运行流程
POJO(Plain Ordinary Java Object)简单的Java对象,实际就是普通JavaBean。
SqlSession就是会话,类似于jdbc里面的Connection,开启了这次会话,就可以发送增删改查的操作,
直到你关闭这个会话。
SqlSessionFactory:生产SqlSession的工厂,作用就是构造返回SqlSession。
1、mybatis配置
SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。
mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。
2、通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂。
3、由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。
4、mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。
5、Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。
6、Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。
7、Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。
Student实体类
无参构造方法比较重要。有参的构造方法根据需要可以写多个。
public class Student {
private int id;
private String name;
private int age;
private String gender;
public Student() {
}
。。。。。。
mybatis.xml
基本配置
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>
<environments default="development">
<environment id="development">
<!-- 使用JDBC的事物管理 -->
<transactionManager type="JDBC"/>
<!-- 配饰数据库连接池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/java?characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="000"/>
</dataSource>
</environment>
</environments>
<!-- 加载映射文件 -->
<mappers>
<mapper resource="com/situ/mybatis/entity/StudentMapper.xml"/>
</mappers>
</configuration>
要格外注意这里
下划线字段对应实体类驼峰命名
<settings>
<!-- 下划线字段对应实体类驼峰命名 数据库表:banji_id 映射到类里面:banjiId -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
配置别名
typeAliases类型别名:alias
<typeAliases>
<!--
<typeAlias alias="Student" type="mybatis.entity.Student"/>
<typeAlias alias="Banji" type="com.situ.mybatis.entity.Banji"/> -->
<!-- 扫描包里面的类,批量起别名,别名即类名,不区分大小写 -->
<package name="mybatis.entity"/>
</typeAliases>
StudentMapper.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>
示例
查
StudentMapper.xml
在这一句里,我们为select标签设置id(会用到);
parameterType 参数(输入)类型,我们传入的参数id的类型Integer);
resultType 结果(输出)类型,输出Student类型,这里写的是具体的包名,如果已经定义过别名就可以直接写Student。
<select id="selectById" parameterType="Integer" resultType="mybatis.entity.Student">
select id, name, age, gender from student where id = #{id}
</select>
<?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="student">//这句很重要,namespace命名空间,用于定位
<select id="selectById" parameterType="Integer" resultType="mybatis.entity.Student">
select id, name, age, gender from student where id = #{id}
</select>
<select id="selectAll" resultType="mybatis.entity.Student">
select id, name, age, gender from student
</select>
</mapper>
test包里面放的是测试类。
这里定义输出类型Student ,后面是我们之前在StudentMapping.xml里namespace.id再加要传入的Integer类型的id。
虽然我们第一个测试类是输出一个Student而第二个测试类输出的是List< Student >集合,但是在StudentMapping.xml里面我们定义的resultType都是Student,因为它能自动检测我们输出的是一个还是多个,多个自动封装。
Student student = sqlSession.selectOne("student.selectById", 4);
public class myBatisTest {
@Test
public void testSelectOne() throws IOException {
String resource = "mybatis.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 执行Mapper.xml中的sql语句
Student student = sqlSession.selectOne("student.selectById", 4);
//这里是namespace.id(select的)
System.out.println(student);
}
@Test
public void testSelectAll() throws IOException {
String resource = "mybatis.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 执行Mapper.xml中的sql语句
List<Student> list = sqlSession.selectList("student.selectAll");
for (Student student : list) {
System.out.println(student);
}
}
MyBatis把JDBC的autocommit设置为false,当执行delete的时候并没有真正提交到数据库,对于更新类的操作需要手动提交。sqlSession.commit();
在JDBC里面默认不需要用户手动提交因为autocommit 默认就是true,执行executeUpdate的时候直接修改了数据库。
删
<select id="deleteById" parameterType="Integer" >
delete from student where id = #{id}
</select>
@Test
public void testDeleteById(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
int count = sqlSession.delete("student.deleteById",4);
System.out.println(count);
sqlSession.commit();
sqlSession.close();
}
改
<select id="update" parameterType="Student">
update student set name = #{name}, age = #{age}, gender = #{gender} where id = #{id}
</select>
@Test
public void testUpdate(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
Student student = new Student();
student.setId(32);
student.setName("王晓晓");
student.setAge(24);
student.setGender("nv");
int count = sqlSession.update("student.update",student);
System.out.println(count);
sqlSession.commit();
}
增
<select id="insert" parameterType="Student">
insert into student(name, age, gender) values (#{name}, #{age}, #{gender})
</select>
@Test
public void testInsert(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
Student student = new Student();
student.setName("王晓晓");
student.setAge(12);
student.setGender("女");
int count = sqlSession.insert("student.insert",student);
System.out.println(count);
sqlSession.commit();
}
Sql片段
Sql中可以将重复代码提取出来,使用include引用,达到sql重用的目的。
<sql id="studentColumn">
id, name, age, gender
</sql>
<select id="selectByPage" parameterType="Map" resultMap="studentMap">
select <include refid="studentColumn"/> from student limit #{offset},#{pageSize}
</select>
输入映射和输出映射总结
输入映射:
parameterType(输入类型)
1、传递简单类型:selectById(Integer id)
使用时候#{id}
2、传递实体类:insert(Student student)
使用时候#{age}括号中的值为实体类中属性的名字。
3、传递Map
<select id="selectByPage" parameterType="Map" resultMap="studentMap">
select <include refid="studentColumn"/> from student limit #{offset},#{pageSize}
</select>
@Test
public void testSelectByPage(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
int pageNo = 2;
int pageSize = 5;
int offset = (pageNo - 1) * pageSize;
Map<String, Object> map = new HashMap<>();
map.put("offset",offset);
map.put("pageSize", pageSize);
List<Student> list = sqlSession.selectList("student.selectByPage",map);
for (Student student : list) {
System.out.println(student);
}
}
输出映射:
1、基本数据类型:
查找一共有多少学生
<select id="selectTotalCount" resultType="Integer">
SELECT count(*) FROM `student`
</select>
@Test
public void testSelectTotalCount() throws IOException {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
int count = sqlSession.selectOne("student.selectTotalCount");
System.out.println("count: " + count);
}
2、输出实体类:Student
3、输出集合:List< Student>
resultMap:
如果查询出来的列名和实体类的属性不一致,通过定义一个resultMap对列名和实体类属性名做一个映射关系。
resultMap 元素是 MyBatis 中最重要最强大的元素。
结果集的映射是 MyBatis 最强大的特性,对其有一个很好的理解的话,许多复杂映射的情形都能迎刃而解。使用 resultMap 或 resultType,但不能同时使用。
当实体类的属性名和表的字段名不一致的时候,必须要写这个映射
id定义主键,result定义普通键;property:类的属性名;column:表的字段名。
<!-- resultMap最终是要将结果映射到Student上
当实体类的属性名和表的字段名不一致的时候,必须要写这个映射 -->
<resultMap type="Student" id="studentMap">
<!-- 映射主键属性:如果有多个主键字段,则定义多个id -->
<!-- property:类的属性名 -->
<!-- column:表的字段名 -->
<id property="id" column="id"/>
<!-- result定义普通属性 -->
<result property="name" column="student_name"/>
<result property="age" column="age"/>
<result property="gender" column="gender"/>
</resultMap>
<select id="selectAll" resultMap="studentMap">
select id,student_name,age,gender from student
</select>