越学接触的越多,到了后面难免会混淆和不知所云。所以记下次笔记,能既多少是多好吧。还有每日学完一章就做好总结,因为回过头再做总结就又要复习一遍,我的记性太差了。
未觉池塘春草梦, 阶前梧叶已秋声。
阶前梧叶已秋声。)
第一章:初识MyBatis
第一节:使用MyBatis框架搭建
我自己根据视频老师将MyBatis框架搭建分了如下步骤,并且记录应该注重的易错点。
梳理步骤:
1:导包(mybatis-3.5.5.jar)
2:准备核心配置文件(用于连接数据库)
3:创建会话工厂(封装有连接,执行,返回结果集的方法)
4:配置映射文件(sql语句)
5:在会话工厂里执行sql语句
实现第一步:导包
1:我的mybatis-3.5.5.jar是在官网上下载了,百度即有。
2:将mybatis-3.5.5.jar放在将包放入:WebCountent下的WEB-INF-lib包下,直接复制黏贴可。
实现第二步:配置核心文件夹
1:在scr的目录下添加xml核心配置文件,建议起名mybatis-config.xml,当然这是自定义的。
2:mybatis的核心配置文件夹内容不需要你死记硬背,你可以在官网也可以在你下载的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">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/school" />
<property name="username" value="root" />
<property name="password" value="123456" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/mapper/TeacherMapper.xml"/>
</mappers>
</configuration>
释:你只需要修改几个属性的值即可,//后都是我的注释,如下是官方样板
<?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"> //一个environment就是一个数据库。 deveopment:开发
<transactionManager type="JDBC"/> //事务管理器
<dataSource type="POOLED"> //数据源:连接池
<property name="driver" value="${driver}"/> //指明驱动类:写在value里,mysql的value值是com.mysql.jdbc.Driver
<property name="url" value="${url}"/> //vslue:jdbc:mysql://localhost:3306/数据库名
<property name="username" value="${username}"/> //value:root
<property name="password" value="${password}"/> //value:123456
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/> </mappers>
</configuration>
释:你只需要修改几个属性的值即可,//后都是我的注释,如下是我根据自己的数据库进行响应的配置
<?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">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/school" />
<property name="username" value="root" />
<property name="password" value="123456" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/mapper/TeacherMapper.xml"/>
</mappers>
</configuration>
注:1:核心文件夹主要用于连接数据库的,当然也需要在这里完成映射文件的注册工作。
2:配置文件是environments容器里可以包裹多个environment容器,这是因为可能会出现多个数据库连接,一般的理解就是一个项目连接一个数据库就行了,那为什么要用到多个数据库是因为我们开发用的一个数据库,开发完之后就有测试数据库,发布后会有一个真实的数据库。所以再不同情况下需要使用不同的数据库喽,最后决定用哪个,再environments标签的default里用environment的id指明就好了
实现第三步:创建会话工厂
1:如何创建如下代码解释如下:
public class Test2 {
public static void main(String[] args) throws Exception {
//第一步:连接数据库
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory =new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session= sqlSessionFactory.openSession();
//第二步:做增删改查操作:sql语句不写在这里,配置在xml文件中:新建一个mapper包
//第三步:执行sql语句
int count= session.selectOne("TeacherMapper.countTeacher");
//查询结果一条记录就叫selectOne 多条就叫selectList 传入的参数就是mapper中的id值
//参数命名:命名空间.id属性,为了避免重复
//第四步:在核心配置文件中配置
System.out.println(count);
session.close();
}
}
实现第四步:配置映射完成增删改查
1:配置映射文件
a、新建一个包:com.mapper专门放对表进行操作的xml文件
b、xml文件起名:表名Mapper.xml 首字母大写
c、复制下面配置信息导xml文件中
2:映射文件内容和核心配置文件一样,去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">
<mapper namespace="TeacherMapper" resultType="int"> //namespace:命名空间,就是起名字地方,为了防止名字重复就起成:表名+Mapper
//resultType="int"要讲清楚你查询结果返回的是什么类型(必填)
//mapper里写增删改查
<select id="countTeacher">
select count(1) from Teacher //注意这里的sql语句不能加分号结束
</select>
</mapper>
3:执行sql语句:在会话工厂里;代码如下:
public class Test2 {
public static void main(String[] args) throws Exception {
//第一步:连接数据库
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory =new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session= sqlSessionFactory.openSession();
//openSession()默认参数是false,关闭事务控制,改成true时增删改成不用再自己控制事务的开启关闭
//第二步:做增删改查操作:sql语句不写在这里,配置在xml文件中:新建一个mapper包
//第三步:执行sql语句
int count= session.selectOne("TeacherMapper.countTeacher");
//查询结果一条记录就叫selectOne 多条就叫selectList 传入的参数就是mapper中的id值
//参数命名:命名空间.id属性,为了避免重复
//第四步:在核心配置文件中配置
System.out.println(count);
session.close();
}
}
4:非常重要的一点,要在核心配置文件中完成映射文件的注册,mapper标签包裹。
<?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">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/school" />
<property name="username" value="root" />
<property name="password" value="123456" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/mapper/TeacherMapper.xml"/>
</mappers>
</configuration>
释:在核心配置文件mybatis-config.xml中用mapper标签配置映射文件,就是告诉数据库你要操作什么表,做什么事
<mappers>
<mapper resource="com/mapper/TeacherMapper.xml"/> //注:1文件夹用/分隔 2.要加.xml 3: 用resource而不是url
</mappers>
第二节:通过接口的方式调用语句
考虑连接需要不停的每次操作一个表就要创建一次连接的问题,我们在之前的基础做以修改,创建一个专门负责连接的类。
梳理思路:
1:需要建立的包:
a、工具包:com.dao放BaseDAO和表的接口
b、接口包:com.dao.impl的实现类
c、测试包:com.dao.test
d、实现包:com.dao.entity
d、映射文件包:com.dao.mapper
2:创建一个com.dao包再创建BaseDAO类来获取连接
3:在接口内添加方法
4:创建一个com.entity包再创建实体类
5:配置映射实现方法文件
6:测试
实现第二步:com.dao包在创建BaseDAO类来获取连接
package com.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.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class BaseDAO {
/*
* 这个类就是为了生成Session工厂会话的:连接对象
* 注意连接成功后不能释放资源
* 单例模式:饿汉模式,线程安全
*/
private static SqlSessionFactory sqlSessionFactory; //此操作为了实现单例模式;如果在方法构建会话工厂就会形成每次调用方法就产生一个新的工厂,耗费资源
private static final String CONFIG_FILE = "mybatis-config.xml"; //静态常量要大写
static {
try {
InputStream inputStream= Resources.getResourceAsStream(CONFIG_FILE);
sqlSessionFactory =new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//建立连接的方法,返回连接对象
public static SqlSession getSession() {
return sqlSessionFactory.openSession();
}
}
实现第三步:创建一个com.entity包再创建实体类
package com.entity;
import java.util.Date;
/*
* 实体类:封装Teacher表
* 1:私有属性 2:get/set方法 3:有参构造 4:无参构造 5:重写toString()方法
*/
public class Teacher {
private Integer teaId;
private String teaName;
private Integer teaAge;
private Date createDate; //注意导包时用util包
public Teacher() {
super();
// TODO Auto-generated constructor stub
}
public Teacher(Integer teaId, String teaName, Integer teaAge, Date createDate) {
super();
this.teaId = teaId;
this.teaName = teaName;
this.teaAge = teaAge;
this.createDate = createDate;
}
public Integer getTeaId() {
return teaId;
}
public void setTeaId(Integer teaId) {
this.teaId = teaId;
}
public String getTeaName() {
return teaName;
}
public void setTeaName(String teaName) {
this.teaName = teaName;
}
public Integer getTeaAge() {
return teaAge;
}
public void setTeaAge(Integer teaAge) {
this.teaAge = teaAge;
}
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
@Override
public String toString() {
return "Teacher [teaId=" + teaId + ", teaName=" + teaName + ", teaAge=" + teaAge + ", createDate="
+ createDate + "]";
}
}
实现第四步:在com.dao包创建增删改查的接口
package com.dao;
import java.util.List;
import com.entity.Teacher;
/*
* 操作表的接口
*
*/
public interface TeacherDAO {
public List<Teacher> getAll(); //查全部方法
}
实现第五步:配置映射文件
注:resultType的值,解释在注释
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dao.TeacherDAO"> <!-- namespace要跟接口的完整限定名一样,不带.java后缀。保证唯一就行了 -->
<select id="getAll" resultType="com.entity.Teacher">
<!-- id的属性要跟接口的方法名一致;记住一定要写resultType,
1:系统可判断返回的是否是集合,所以不用指明list,只需要告诉它集合里装的是什么元素类型
2:如果写的是实体类的类型,就要写实体类的完整限定名,我这里是这里是Teacher,要写包名.Teacher
-->
select * from teacher
</select>
</mapper>
实现第六步:测试
package com.test;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import com.dao.BaseDAO;
import com.dao.TeacherDAO;
import com.entity.Teacher;
/*
* 测试类
*/
public class Test {
public static void main(String[] args) {
SqlSession session = BaseDAO.getSession(); //1:拿到session对象,获得连接
TeacherDAO dao = session.getMapper(TeacherDAO.class); //2:拿到映射文件返回对应接口
List<Teacher> tealist= dao.getAll(); //3:执行接口中的方法
System.out.println(tealist.size());
//4:循环遍历
for (Teacher t : tealist) {
System.out.println(t); //我这里是重写了toString()方法
}
//5:关
session.close();
}
}
第三节:使用MyBatis实现简单的增删改
梳理思路:
1:先将对应数据库的驱动和MyBatis的jar包加入项目内,位置放在eclipse的Webcount下的WEB-INF下的lib文件夹。
2:根据数据库信息配置核心配置文件。
3:在com.dao包下建立BaseDAO用于专门连接创建session对象。
4:前三步已经在第二章时已经操作过了,我们直接从接口内添加方法开始,注意接口内的每一个方法都要在映射文件内实现。
5:在接口继续添加增删改的方法
6:在映射文件补充实现方法;
7:测试包内的测试类
实现第五步:在接口添加方法
直接上代码,内有注释;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import com.entity.Teacher;
/*
* 操作表的接口
*
*/
public interface TeacherDAO {
public List<Teacher> getAll(); //查全部方法
public void delect(Integer teaId);
//1:根据id删除 2:返回值可以是int,但是不用在映射文件中指明resultType,再被方法调用的时候可以用int接收,拿到受影响行数
public int add(@Param("tea") Teacher tea); //当在映射文件的sql语句传入多个参数就需要用到注解@Param("tea") 传一个就无需注解
}
实现第六步:在映射文件中实现接口方法
直接上代码,内有注释;
<?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="com.dao.TeacherDAO"> <!-- namespace要跟接口的完整限定名一样,不带.java后缀。保证唯一就行了 -->
<select id="getAll" resultType="com.entity.Teacher">
<!-- id的属性要跟接口的方法名一致;记住一定要写resultType,
1:系统可判断返回的是否是集合,所以不用指明list,只需要告诉它集合里装的是什么元素类型
2:如果写的是实体类的类型,就要写实体类的完整限定名,我这里是这里是Teacher,要写包名.Teacher
-->
select * from teacher
</select>
<delete id="delect" >
delete from teacher where teaId=#{teaId)} <!-- #{}传入的参数是接口里方法需要传入的参数名 -->
</delete>
<insert id="add">
insert into Teacher value(null,#{tea.teaName},#{tea.teaAge},#{tea.createDate})
</insert>
</mapper>
实现第七步:测试类
测试删类;
package com.test;
import org.apache.ibatis.session.SqlSession;
import com.dao.BaseDAO;
import com.dao.TeacherDAO;
public class Test2 {
public static void main(String[] args) {
SqlSession session= BaseDAO.getSession();
TeacherDAO dao = session.getMapper(TeacherDAO.class);
dao.delect(2);
session.commit(); //这里需要我们自己完成事务的提交
session.close();
}
}
测试添加;
package com.test;
import java.util.Date;
import org.apache.ibatis.session.SqlSession;
import com.dao.BaseDAO;
import com.dao.TeacherDAO;
import com.entity.Teacher;
public class Teat3 {
public static void main(String[] args) {
SqlSession session= BaseDAO.getSession();
TeacherDAO dao = session.getMapper(TeacherDAO.class);
Teacher tea = new Teacher(4,"仙女",18,new Date());
int num= dao.add(tea); //只要接口里的方法返回值是int类型就可以在这里拿到受影响行数,无需了resultType
System.out.println(num);
session.commit(); //这里需要我们自己完成事务的提交
session.close();
}
}
第二章:SQL映射文件
第一节:单个参数的传递
参数传递是什么
一:参数传递是什么:就是我们在定义接口是,为接口方法传递的参数值
为什么要学单个参数的传递
二:为什么要学单个参数的传递:其实单个没啥好说的,因为只有一个参数,只传一个就行,不会混淆。
怎么实现
三:怎么传:
1:建工程将你需要的数据库驱动包、MyBatis的jar包添加到WebCount下的WEB-INF下的lib;
2:在scr的根目录下加核心配置文件:mybatis-config.xml文件,这个文件的作用是配置数据库的连接信息;
3:分别建包:dao、entity、imple、mapper;
4:创建实体类;
5:在dao包下创建BaseDAO(专门生产session会话)和操作数据库的接口;
6:在mapper包里创建实现接口方法的映射文件,文件名一般叫表名Mapper.xml;并完成在映射文件的注册;
注:1-6步在上一章已经有说明,这里就不再搬砖了;
7:用JUnit进行测试;
第七步:用JUnit进行测试:
- 是什么:java方向的一个第三方的单元测试工具
- 为什么用:不用在main函数下运行
- 怎么用:右击项目——Build Path——Libraies——Add Libraies——选JUnit; 代码注释有如何使用;
public class TestTeacherDao {
@Test // 如果这里报错不是没将JUnit导入项目,还有就是导了项目却没导包
public void testGetById() { // 运行:选中testGetById()右击Run as——Junit Test
SqlSession session = BaseDAO.getSession(); // 拿到session会话完成连接,并拿到相应的API
TeacherDAO dao = session.getMapper(TeacherDAO.class); // 将接口(mapper是接口的实现)放入会话工厂返回一个接口
Teacher tea = dao.getById(1);
System.out.println(tea);
}
}
第二节:单个对象的传递
单个对象传递是什么:
一:以单个对象作为参数传递给sql语句。
为什么要学单个对象的传递
二:当我们传单个对象,不会混淆,直接用属性传参就行了,不用对象.属性名。
怎么实现
三:怎么传:
1:建工程将你需要的数据库驱动包、MyBatis的jar包添加到WebCount下的WEB-INF下的lib;
2:在scr的根目录下加核心配置文件:mybatis-config.xml文件,这个文件的作用是配置数据库的连接信息;
3:分别建包:dao、entity、imple、mapper;
4:创建实体类;
5:在dao包下创建BaseDAO(专门生产session会话)和操作数据库的接口;
6:在mapper包里创建实现接口方法的映射文件,文件名一般叫表名Mapper.xml;并完成在映射文件的注册;
注:1-6步在上一章已经有说明,这里就不再搬砖了;
7:以单个对象作为参数传递
8:用JUnit进行测试;
第七步:单个对象作为参数传递:
<?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="com.dao.TeacherDAO"> <!-- 命名空间要写你要实现接口的完整限定名,不带后缀 -->
//以单个基本类型传参
<select id="getById" resultType="com.entity.Teacher"> <!-- 如果返回的是对象(实体类)返回值要写完整限定名 -->
select * from Teacher where teaId=#{teaId} <!-- 这里不写分号结束,其实我自己写了,没报错 -->
</select>
//以单个对象传参
<insert id="add">
insert into teacher values(null,#{ teaName},#{teaAge},#{createDate})
</insert>
</mapper>
<!--
MyBatis传参:
1:单个参数
a、基本数据类型:参数名自定义,因为只有一个参数所以不会混淆,但一般会跟参数相同
b、如入的是对象类型,则直接写对象的属性名即可
-->
**第八步:用JUnit进行测试:**
@Test
public void testAdd() {
SqlSession session = BaseDAO.getSession(); // 拿到session会话完成连接,并拿到相应的API
TeacherDAO dao = session.getMapper(TeacherDAO.class); // 将接口(mapper是接口的实现)放入会话工厂返回一个接口
Teacher tea = new Teacher(6,"张三",22,new Date());
int num = dao.add(tea);
Assert.assertEquals(num, 1); 断言:如果num==1就通过,否则JUnit不通过
session.commit(); //除了查询,增删改都要提交事务
session.close();
}
第三节:多个对象参数的传递
多个对象参数是什么:
一:以单个对象作为参数传递时,映射文件应该怎么写
为什么要学多个对象参数
二:当我们传单个对象,不会混淆,直接用属性传参就行了
怎么实现
第二节的项目,只改动(添加)了接口、映射文件、测试类,上代码
接口
public interface TeacherDAO {
//根据主键查询学生
public Teacher getById(int teaId);
//以单个对象作为参数传递
public int add(Teacher tea);
//以多个对象参数传递:映射问价直接用@Param("name") 里的name代号传参
public List<Teacher> getByNameByAge(@Param("name") String teaName,@Param("age")Integer teaAge);
}
映射文件
<?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="com.dao.TeacherDAO"> <!-- 命名空间要写你要实现接口的完整限定名,不带后缀 -->
<!-- 传单个基本参数 -->
<select id="getById" resultType="com.entity.Teacher"> <!-- 如果返回的是对象(实体类)返回值要写完整限定名 -->
select * from Teacher where teaId=#{teaId} <!-- 这里不写分号结束,其实我自己写了,没报错 -->
</select>
<!-- 传单个对象参数 -->
<insert id="add">
insert into teacher values(null,#{ teaName},#{teaAge},#{createDate})
</insert>
<!-- 传多个对象参数 -->
<select id="getByNameByAge" resultType="com.entity.Teacher"> <!-- 系统会自动识别返回的是集合,你只需要指明集合类型就可以 -->
select * from Teacher where teaName=#{name} and teaAge=#{age}
</select>
</mapper>
<!--
MyBatis传参:
1:单个参数
a、基本数据类型:参数名自定义,因为只有一个参数所以不会混淆,但一般会跟参数相同
b、如入的是对象类型,则直接写对象的属性名即可
2:多个参数
a、可以用下标表示,例如:#{0} #{1}
b、可以用参数关键字表示 例如:#{param1} #{param2}
c、用一个Map装多个参数,取值的时候用的是key,#{key}
以上解决反案都不咋的
d、用的最多的就是在定义方法时就给参数另起名:(@Param("name") String teaName,@Param("age")Integer teaAge);
-->
测试类
public class TestTeacherDao {
@Test // 如果这里报错不是没将JUnit导入项目,还有就是导了项目却没导包
public void testGetById() { // 运行:选中testGetById()右击Run as——Junit Test
SqlSession session = BaseDAO.getSession(); // 拿到session会话完成连接,并拿到相应的API
TeacherDAO dao = session.getMapper(TeacherDAO.class); // 将接口(mapper是接口的实现)放入会话工厂返回一个接口
Teacher tea = dao.getById(1);
System.out.println(tea);
session.close();
}
@Test
public void testAdd() {
SqlSession session = BaseDAO.getSession(); // 拿到session会话完成连接,并拿到相应的API
TeacherDAO dao = session.getMapper(TeacherDAO.class); // 将接口(mapper是接口的实现)放入会话工厂返回一个接口
Teacher tea = new Teacher(6,"张三",22,new Date());
int num = dao.add(tea);
Assert.assertEquals(num, 1); 断言:如果num==1就通过,否则JUnit不通过
session.commit(); //除了查询,增删改都要提交事务
session.close();
}
@Test
public void selStuTest() {
SqlSession session = BaseDAO.getSession(); // 拿到session会话完成连接,并拿到相应的API
TeacherDAO dao = session.getMapper(TeacherDAO.class); // 将接口(mapper是接口的实现)放入会话工厂返回一个接口
List<Teacher> teaList=dao.getByNameByAge("仙女", 18);
System.out.println(teaList);
session.close();
}
}
第四节:类型别名
概念
类型别名:在映射文件中的resultType的值,可以省略完整限定名,只需类名(两种方法)。基本数据类型系统会自动配置;
为什么用它
因为我们要处理方法的返回值类型鸭,方便鸭,减少代码
怎么用
经过之前的学习我们已经了解到:
1:返回基本类型就写基本类型,如果是int返回受影响的行数,可以省略resultType;
2:返回对象就写对象对应实体类的完整限定名;
3:返回集合也只需写集合返回类型对应实体类的完整限定名;
现在我们学另外一种方式:类型别名
怎么做:
1:去核心配置文件添加一个标签:
2:去修改映射文件的resultType的值
第一步:配置核心配置文件1:
<?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>
<typeAliases>
<typeAlias type="com.entity.Teacher" alias="Teacher"/> <!-- 为映射文件中的resultType起别名 -->
</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/school" />
<property name="username" value="root" />
<property name="password" value="123456" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/mapper/TeacherMapper.xml"/>
</mappers>
</configuration>
第一步:配置核心配置文件2:
<?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>
<typeAliases>
<package name="com.entity"/> <!-- 类型别名:直接给把包传进去,系统会先从配置文件中找到包,再从包中找实体类 -->
</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/school" />
<property name="username" value="root" />
<property name="password" value="123456" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/mapper/TeacherMapper.xml"/>
</mappers>
</configuration>
第二步:修改映射文件值
<?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="com.dao.TeacherDAO"> <!-- 命名空间要写你要实现接口的完整限定名,不带后缀 -->
<!-- 传单个基本参数 -->
<select id="getById" resultType="Teacher"> <!-- 如果返回的是对象(实体类)返回值要写完整限定名 -->
select * from Teacher where teaId=#{teaId} <!-- 这里不写分号结束,其实我自己写了,没报错 -->
</select>
<!-- 传单个对象参数 -->
<insert id="add">
insert into teacher values(null,#{ teaName},#{teaAge},#{createDate})
</insert>
<!-- 传多个对象参数 -->
<select id="getByNameByAge" resultType="Teacher"> <!-- 系统会自动识别返回的是集合,你只需要指明集合类型就可以 -->
select * from Teacher where teaName=#{name} and teaAge=#{age}
</select>
</mapper>
<!--
MyBatis传参:
1:单个参数
a、基本数据类型:参数名自定义,因为只有一个参数所以不会混淆,但一般会跟参数相同
b、如入的是对象类型,则直接写对象的属性名即可
2:多个参数
a、可以用下标表示,例如:#{0} #{1}
b、可以用参数关键字表示 例如:#{param1} #{param2}
c、用一个Map装多个参数,取值的时候用的是key,#{key}
以上解决反案都不咋的
d、用的最多的就是在定义方法时就给参数另起名:(@Param("name") String teaName,@Param("age")Integer teaAge);
typeAliases:类型别名
-->
第五节:模糊查找
是什么:
用like关键字进行模糊查询
为什么:
规则,没有为什么
怎么用
<?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="com.dao.TeacherDAO"> <!-- 命名空间要写你要实现接口的完整限定名,不带后缀 -->
<!-- 传单个基本参数 -->
<select id="getById" resultType="Teacher"> <!-- 如果返回的是对象(实体类)返回值要写完整限定名 -->
select * from Teacher where teaId=#{teaId} <!-- 这里不写分号结束,其实我自己写了,没报错 -->
</select>
<!-- 传单个对象参数 -->
<insert id="add">
insert into teacher values(null,#{ teaName},#{teaAge},#{createDate})
</insert>
<!-- 传多个对象参数 -->
<select id="getByNameByAge" resultType="Teacher"> <!-- 系统会自动识别返回的是集合,你只需要指明集合类型就可以 -->
select * from Teacher where teaName=#{name} and teaAge=#{age}
</select>
<!-- 模糊查找 -->
<select id="getByName" resultType="Teacher">
select * from teacher where teaname like concat('%',#{name},'%')
</select>
</mapper>
<!--
MyBatis传参:
1:单个参数
a、基本数据类型:参数名自定义,因为只有一个参数所以不会混淆,但一般会跟参数相同
b、如入的是对象类型,则直接写对象的属性名即可
2:多个参数
a、可以用下标表示,例如:#{0} #{1}
b、可以用参数关键字表示 例如:#{param1} #{param2}
c、用一个Map装多个参数,取值的时候用的是key,#{key}
以上解决反案都不咋的
d、用的最多的就是在定义方法时就给参数另起名:(@Param("name") String teaName,@Param("age")Integer teaAge);
typeAliases:类型别名
-->
测试:
@Test //模糊查找
public void selectlike() {
SqlSession session = BaseDAO.getSession(); // 拿到session会话完成连接,并拿到相应的API
TeacherDAO dao = session.getMapper(TeacherDAO.class); // 将接口(mapper是接口的实现)放入会话工厂返回一个接口
//select concat('a','b','c')
List<Teacher> teaList=dao.getByName("li");
System.out.println(teaList.size());
session.close();
}
第六节:简单的结果集映射
是什么:
将查询的结果通过相同的名字(表字段和实体类属性)赋值的过程就叫结果集映射。
为什么用它:
因为会存在数据库表的列和实体类的属性名不一致。所以映射不一致,就会存在查不到相应的内容。
怎么用:
配置映射文件
<!-- 查询全部:结果集映射 -->
<!-- 此处用于描述数据库的teacher表查询结果如何和实体类Teacher映射 -->
<resultMap type="Teacher" id="teacherMap">
<!-- 此处用于映射属性和字段不同名 column赋值数据库字段 主键用id映射 除主键外都用result映射 -->
<id column="teaId" property="teaId" />
<result column="tea_Name" property="teaName" />
</resultMap> <!-- id自定义,将这个id查询结果赋值给type的实体类Teacher -->
<!-- resultMap和resultType只能有一个 -->
<select id="getAlltea" resultMap="teacherMap"> <!-- resultMap结果映射:值是描述映射的id值 -->
select * from teacher
</select>
测试
@Test //查全部
public void selecAll() {
SqlSession session = BaseDAO.getSession(); // 拿到session会话完成连接,并拿到相应的API
TeacherDAO dao = session.getMapper(TeacherDAO.class); // 将接口(mapper是接口的实现)放入会话工厂返回一个接口
//select concat('a','b','c')
List<Teacher> teaList=dao.getAlltea();
for(Teacher t:teaList) {
System.out.println(t);
}
session.close();
}
以细行律身,不可以细行取人。
第七节:输出日志信息
是什么?
在控制台可查看方法具体执行了哪些内容,比如那条sql语句。
为什么用它?
可查看程序运行的详细过程。
怎么做?
第一步:在src下添加log4j.properties的配置文件
第二步:在lib文件夹下添加log4j.jar包
第三步:在核心配置文件里添加settings标签引入log4
注:核心配置文件添加setting标签
<!-- 配置mybatis的log实现为LOG4J:1:properties文件 2:log4j.jar包 3:核心配置文件的settings标签-->
<settings>
<setting name="logImpl" value="LOG4J" />
</settings>
第八节:定义多对一情况的实体类
是什么?
当出现两表查询的时候,那肯定有两个实体类。那那查询出来的结果到底要映射那张表合适,其实都不合适。
为什么?
当两个实体类都达不到映射表结果的效果就要在拥有外键的那张表(实体类)做操作。
怎么做?
需求:年级表:gradeid
name
学生表:id
name
age
sex
britherday
gradeid
干啥:在页面上显示学生信息列表:
学生ID 姓名 年龄 性别 生日 年级名称
步骤:1:先键实体类,外键字段在实体类中,会定义为引用对象。
第一步:建实体类
学生实体类
public class Student {
private Integer stuId;
private String stuName;
private String stuAge;
private String stuSex;
private String stuBrithday;
//外键字段在实体类中,会定义为引用对象,是否实例化都没关系;
private Grade grade; //年级对学生是多对一
public Integer getStuId() {
return stuId;
}
public void setStuId(Integer stuId) {
this.stuId = stuId;
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
public String getStuAge() {
return stuAge;
}
public void setStuAge(String stuAge) {
this.stuAge = stuAge;
}
public String getStuSex() {
return stuSex;
}
public void setStuSex(String stuSex) {
this.stuSex = stuSex;
}
public String getStuBrithday() {
return stuBrithday;
}
public void setStuBrithday(String stuBrithday) {
this.stuBrithday = stuBrithday;
}
public Grade getGrade() {
return grade;
}
public void setGrade(Grade grade) {
this.grade = grade;
}
}
班级实体类
public class Grade {
private Integer gradeId;
private String gradeName;
public Integer getGradeId() {
return gradeId;
}
public void setGradeId(Integer gradeId) {
this.gradeId = gradeId;
}
public String getGradeName() {
return gradeName;
}
public void setGradeName(String gradeName) {
this.gradeName = gradeName;
}
public Grade() {
super();
// TODO Auto-generated constructor stub
}
public Grade(Integer gradeId, String gradeName) {
super();
this.gradeId = gradeId;
this.gradeName = gradeName;
}
@Override
public String toString() {
return "Grade [gradeId=" + gradeId + ", gradeName=" + gradeName + "]";
}
}
第二步:建学生DAO接口
public interface StudentDAO {
public List<Student> getAll(); //查询学生信息,连带班级信息
}
第三步:建BaseDAO类
直接把上一章的复制过来
第四步:建学生DAO接口实现类
public class StudentDAOImpl implements StudentDAO{
@Override
public List<Student> getAll() {
SqlSession session = BaseDAO.getSession();
StudentDAO dao =session.getMapper(StudentDAO.class);
List<Student> liststu =dao.getAll();
return liststu;
}
}
第五步:映射文件的编写!重点
<mapper namespace="com.dao.StudentDAO"> <!-- 命名空间要写你要实现接口的完整限定名,不带后缀 -->
<!-- 实体类的属性和表的字段不匹配就需要写结果集映射 -->
<resultMap type="Student" id="StudentMap">
<result column="gradeId" property="grade.gradeId"/> <!--实体类中引用类型属性的映射写法 -->
<result column="gradeName" property="grade.gradeName"/>
</resultMap>
<select id="getAll" resultMap="StudentMap">
select * from student s INNER join grade g on s.gradeId=g.gradeId
</select>
</mapper>
第六步:测试
public class test {
@Test
public void testgetall() {
StudentDAO dao = new StudentDAOImpl();
List<Student> listStu = dao.getAll();
for(Student s:listStu) {
System.out.println(s);
}
}
}
第十节:多对一的映射方式2_association标签
是什么?
映射基本复杂类型(实体类)
可以在映射文件中,直接关联子表中的外键(主表),达到两表联查的效果。
为什么?
比上一节的代码清晰,可读性好。
怎么做?
主要在映射文件配置
<mapper namespace="com.dao.StudentDAO"> <!-- 命名空间要写你要实现接口的完整限定名,不带后缀 -->
<!-- 实体类的属性和表的字段不匹配就需要写结果集映射 -->
<resultMap type="Student" id="StudentMap">
//<!-- <result column="gradeId" property="grade.gradeId"/> 实体类中引用类型属性的映射写法
//<result column="gradeName" property="grade.gradeName"/> 被assocation替代
// -->
//association:关联 当关联表查询时,拥有外键的实体类将关联实体类作为属性时
//property的值写拥有外键实体类的属性值 javaType是映射的实体类对象
<association property="grade" javaType="Grade"> //这里可以将assocation里的id,result标签放在外部,在association添加一个外部resultMap的id属性即可。
<id column="gradeId" property="gradeId"/> // <!--column:数据库的属性,property:实体类的属性 -->
<result column="gradeName" property="gradeName"/>
</association>
</resultMap>
<select id="getAll" resultMap="StudentMap">
select * from student s INNER join grade g on s.gradeId=g.gradeId
</select>
</mapper>
第十一节:ResultMap的引用
是什么?
引用别的Mapper里的resultMap
为什么?
比如现在的学生mapper和班级mapper一摸一样,所以才去只写一个mapper,之后直接引用这个即可,简化代码。
怎么做?
resyltMap=“name.id”;
name:要引用Mapper的命名空间,id是指要引用Mapper里的resultMapper的id属性值
<?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="com.dao.StudentDAO">
<resultMap type="Student" id="StudentMap">
//<!-- 引用别的Mapper里的resultMap时要在前面加上要引用Map的namespacs.id -->
<association property="grade" javaType="Grade" resultMap="com.dao.GradeDAO.boosGradeMap"/>
</resultMap>
<select id="getAll" resultMap="StudentMap">
select * from student s INNER join grade g on s.gradeId=g.gradeId
</select>
</mapper>
第十二节:ResultMap的继承extends
是什么?
利用extends=被继承resultMap的id值,可以实现继承resultMap的代码
为什么?
实现代码重用,简化代码
怎么做?
extends=被继承id属性值
<mapper namespace="com.dao.StudentDAO">
// <!-- student自身基本属性 -->
<resultMap type="Student" id="boosStudentMap">
<id column="stuId" property="stuId" />
<result column="stuName" property="stuName" />
<result column="stuSex" property="stuSex" />
<result column="stuBrithday" property="stuBrithday" />
</resultMap>
// <!--student属性+grade属性
// extends属性可以继承其他resultMap,值写被引用resultMap的id值
// -->
<resultMap type="Student" id="fullStudentMap" extends="boosStudentMap">
// <!-- 引用别的Mapper里的resultMap时要在前面加上要引用Map的namespacs.id -->
<association property="grade" javaType="Grade"
resultMap="com.dao.GradeDAO.boosGradeMap" />
</resultMap>
<select id="getStuWithGra" resultMap="fullStudentMap">
select * from student s INNER join grade g on s.gradeId=g.gradeId
</select>
<select id="getStuAll" resultMap="boosStudentMap">
select * from student
</select>
</mapper>
第十三节:一对多映射collection标签
是什么?
映射超复杂类型,比如集合
和association一样,都用于多表关联时使用。
为什么?
因为映射的不是一个普通的实体类,而是实体类集合,所以association就不能用了;
怎么做?
collection标签的使用
<mapper namespace="com.dao.GradeDAO"> // <!-- 命名空间要写你要实现接口的完整限定名,不带后缀 -->
<resultMap type="Grade" id="boosGradeMap">
<id column="gradeId" property="gradeId"/>
<result column="gradeName" property="gradeName"/>
</resultMap>
// <!--超复杂对象关联映射用collection -->
<resultMap type="Grade" id="fullGradeMap" extends="boosGradeMap">
// <!--配置集合属性 -->
<collection property="students" ofType="Student" resultMap="com.dao.StudentDAO.boosStudentMap"/> //这里直接引用StudentMapper的resultMapper
// <!--collection集合里的students的类型是Student resultMap:的引用 -->
</resultMap>
<select id="getAllGra" resultMap="boosGradeMap">
select * from Grade
</select>
<select id="getAllwithStu" resultMap="fullGradeMap">
select * from student s INNER join grade g on s.gradeId=g.gradeId
</select>
</mapper>
测试:
@Test
public void findGrawithStu() {
GradeDAO dao = new GradeDAOImpl();
List<Grade> graList=dao.getAllwithStu();
for(Grade g:graList) {
System.out.println(g.getGradeName());
List<Student> stuList = g.getStudents();
for(Student s:stuList) {
System.out.println("\t"+s.getStuName());
}
}
}
第十四节:总结和自动匹配级别##
是什么?
设置在核心配置文件中的settings标签,settings属性是MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。具有name属性以及相对应的values值。
为什么?
我们这里设置的是自动匹配行为(匹配级别)NONE/PARTIAL(默认值)/FULL
- NONE:不自动匹配
- PARTIAL:部分匹配(当你的结果映射里面包含association/collection时不匹配没有设置过的属性)
- FULL:完整匹配
怎么做?
<!--自动匹配行为(匹配级别)NONE/PARTIAL(默认值)/FULL
NONE:不自动匹配
PARTIAL:部分匹配(当你的结果映射里面包含association/collection时不匹配)
FULL:完整匹配
-->
<settings>
<setting name="autoMappingBehavior" value="PARTIAL"/>
</settings>
第三章:动态sql
第一节:if标签
是什么?
用于sql语句作为条件判断的。
为什么用它?
判断传入字符串是否为空。
怎么用
<select id="getStu" resultType="Student">
select * from student where 1=1 // <!--1=1是横成立,表示查全部 -->
<if test="stu.stuName!=null and stu.stuName!='' "> <!-- 切记空字符串内不要用空格 -->
and stuName=#{stu.stuName}
</if>
<if test="stu.stuAge!=null">
and stuAge=#{stu.stuAge}
</if>
<if test="stu.stuSex!=null and stu.stuSex!='' ">
and stuSex=#{stu.stuSex}
</if>
</select>
第二节:where标签
是什么
if-where:if条件匹配时自动添加where,会自动去掉跟进where后面的and/or
为什么用
比单用if方便
怎么用
<!--if-where标签 -->
<select id="getStu" resultType="Student">
select * from student where <!--1=1是横成立,表示查全部 -->
<where>
<if test="stu.stuName!=null and stu.stuName!='' "> // <!-- 切记空字符串内不要用空格 -->
and stuName=#{stu.stuName}
</if>
<if test="stu.stuAge!=null">
and stuAge=#{stu.stuAge}
</if>
<if test="stu.stuSex!=null and stu.stuSex!='' ">
and stuSex=#{stu.stuSex}
</if>
</where>
</select>
第三节:trim标签
是什么
prefix:前缀增加
suffix:后缀增加
prefixOverrides:前缀去除
suffixOverrides:后缀去除
意为:如果if条件判断成立,就给if条件前加一个where,并且去掉where紧跟的and.or
和if-where本质是一样的.可以替代where/set
为什么用
本质和if-where是一样的,根据方法被调用时传入的串是否为空,达到拼接sql语句的效果。
怎么用
<select id="getStu" resultType="Student">
select * from student
<trim prefix="where" prefixOverrides="and/or">
<if test="stu.stuName!=null and stu.stuName!='' "> // <!-- 切记空字符串内不要用空格 -->
and stuName=#{stu.stuName}
</if>
<if test="stu.stuAge!=null">
and stuAge=#{stu.stuAge}
</if>
<if test="stu.stuSex!=null and stu.stuSex!='' ">
and stuSex=#{stu.stuSex}
</if>
</trim>
</select>
第四节:set标签
是什么
用于操作修改的sql语句的标签,通过判断传入参数是否为空来进行sql语句的拼接。
为什么用
- set标签会给你加一个set关键字开头
- 把多余的逗号去掉
怎么用
一:实现方法
@Override
public Integer update(Student stu) {
SqlSession session = BaseDAO.getSession();
StudentDAO dao = session.getMapper(StudentDAO.class);
int num = dao.update(stu);
session.commit(); //除了查询,其他操作都要提交事务,注意是在调用方法后回滚事务,不然没有查询结果。
return num;
}
一:编写sql语句
<update id="update">
update student
<set>
<if test="stu.stuName!=null and stu.stuName!='' "> // <!-- 切记空字符串内不要用空格 -->
stuName=#{stu.stuName}, // <!--修改语句没有and -->
</if>
<if test="stu.stuAge!=null">
stuAge=#{stu.stuAge},
</if>
<if test="stu.stuSex!=null and stu.stuSex!='' ">
stuSex=#{stu.stuSex},
</if>
</set>
where stuId=#{stu.stuId}
</update>
二:测试
@Test
public void uodateStu() {
StudentDAO dao = new Studentimpl();
Student stu = new Student();
stu.setStuId(3);
stu.setStuName("王五2");
dao.update(stu);
}
第五节:choose标签
是什么
是sql语句中用于传参是的标签,应用于多个if条件存在排斥的时候,就要用choose-when
为什么用
用于只允许一个参数传递,如果有id,则按ID查,没有ID,则按姓名查,没有姓名,则根据性别差,负责根据年龄差。
怎么用
第六节:foreach标签
是什么
针对方法需要传入数组/集合是就用foreach标签
eg: select * from student where stuId in(1,2,3);这类语句
为什么
需要循环遍历输出,批量查询
怎么用
一:接口
//foreach标签处理sql里in传入的值
public List<Student> sels(@Param("stuList") int[] ass);
public List<Student> sels(@Param("stuList") List list);
public List<Student> sels(@Param("stuList") Map map);
二:实现方法
//foreach标签用Map传入sql里的in(.....)
@Override
public List<Student> sels(Map map) {
SqlSession session = BaseDAO.getSession();
StudentDAO dao = session.getMapper(StudentDAO.class);
return dao.sels(map);
}
//foreach标签用数组传入sql里的in(.....)
@Override
public List<Student> sels(int[] ass) {
SqlSession session = BaseDAO.getSession();
StudentDAO dao = session.getMapper(StudentDAO.class);
return dao.sels(ass);
}
//foreach标签用List集合传入sql里的in(.....)
@Override
public List<Student> sels(List list) {
SqlSession session = BaseDAO.getSession();
StudentDAO dao = session.getMapper(StudentDAO.class);
return dao.sels(list);
}
二:映射文件内的sql语句
<!--foreach的用法 -->
<select id="sels" resultType="Student">
select * from student where stuId in
<foreach collection="stuList" item="elm" open="(" close=")" separator=","> <!-- -->
#{elm}
</foreach>
</select>
//foreach标签写法固定,要注意的是item="elm"里的elm是你接收进来的值(迭代变量),也是需要以它为条件做循环遍历出来的,如果是传入的是集合,collection为list
三:测试
//foreach标签 用数组传入sql语句里的in(.....)
@Test
public void forech() {
StudentDAO dao = new Studentimpl();
int[] ids= {3,4};
List<Student> listStu= dao.sels(ids);
for(Student s:listStu ) {
System.out.println(s);
}
}
//foreach标签 用Map传入sql语句里的in(.....)
@Test
public void foreachMap() {
StudentDAO dao = new Studentimpl();
Map map = new HashMap();
map.put("stuId1", 10);
map.put("stuId2", 11);
map.put("stuId3", 12);
List<Student> listStu=dao.sels(map);
System.out.println(listStu.size());
for(Student s:listStu ) {
System.out.println(s);
}
}
//foreach标签 用List传入sql语句里的in(.....)
@Test
public void foreachList() {
StudentDAO dao = new Studentimpl();
List list = new ArrayList();
list.add(10);
list.add(11);
list.add(12);
List<Student> listStu=dao.sels(list);
System.out.println(listStu.size());
for(Student s:listStu ) {
System.out.println(s);
}
}
第七节:利用标签实现分页
第四章:阶段训练
需求:
- 做一个Teacher的添加
- 查询所有Teacher对象
- 提高给Servlet调用
- Servlet 调用Mybatis的内容