文章目录
一、mybatis查询基本操作
1.MyBatis解决的问题:
- 减轻使用 JDBC 的复杂性,不用编写重复的创建 Connetion , Statement ; 不用编写关闭资源代码。
- 直接使用 java 对象,表示结果数据。让开发者专注 SQL 的处理。 其他分心的工作由 MyBatis 代劳
2.MyBatis可以完成的工作:
- 注册数据库的驱动,例如 Class.forName(“com.mysql.jdbc.Driver”))
- 创建 JDBC 中必须使用的 Connection , Statement, ResultSet 对象
- 从 xml 中获取 sql,并执行 sql 语句,把 ResultSet 结果转换 java 对象
查询操作:
1.1 创建数据库与表
- student表
CREATE TABLE `student` (
`id` int NOT NULL,
`name` varchar(255) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`age` int DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
1.2 创建maven工程
- 导入坐标
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.25</version>
</dependency>
- 加入maven插件
<build>
<resources>
<resource>
<directory>src/main/java</directory><!--所在的目录-->
<includes><!--包括目录下的.properties,.xml 文件都会扫描到-->
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
1.3 创建实体类
- Student实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private Integer id;
private String name;
private String email;
private Integer age;
}
- 创建Dao接口StudentDao
public interface StudentDao {
//查询student表中所有的数据
public List<Student> ListAll();
}
1.4 编写 Dao 接口 Mapper 映射文件 StudentDao.xml
1. 在 dao 包中创建文件 StudentDao.xml
2. 要 StudentDao.xml 文件名称和接口 StudentDao 一样,区分大小写的一样
<?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">
<!-- sql映射文件(sql mapper): 写sql语句的, mybatis会执行这些sql
1.指定约束文件
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
mybatis-3-mapper.dtd是约束文件的名称, 扩展名是dtd的。
2.约束文件作用:限制,检查在当前文件中出现的标签,属性必须符合mybatis的要求。
3.mapper 是当前文件的根标签,必须的。
namespace:叫做命名空间,唯一值的, 可以是自定义的字符串。
要求你使用dao接口的全限定名称。-->
<mapper namespace="com.jjh.dao.StudentDao">
<!--
4.在当前文件中,可以使用特定的标签,表示数据库的特定操作。
<select>:表示执行查询,select语句
<update>:表示更新数据库的操作, 就是在<update>标签中 写的是update sql语句
<insert>:表示插入, 放的是insert语句
<delete>:表示删除, 执行的delete语句
-->
<!--
select:表示查询操作。
id: 你要执行的sql语法的唯一标识, mybatis会使用这个id的值来找到要执行的sql语句
可以自定义,但是要求你使用接口中的方法名称。
resultType:表示结果类型的,是sql语句执行后得到ResultSet,遍历这个ResultSet得到java对象的类型。
值写的类型的全限定名称
-->
<select id="ListAll" resultType="com.jjh.domain.dto.Student">
select * from student order by id;
</select>
</mapper>
1.5 创建 MyBatis 主配置文件
- 项目 src/main 下创建 resources 目录,设置 resources 目录为 resources root
- 创建主配置文件:名称为 mybatis.xml
<?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>
<!--settings:控制mybatis全局行为-->
<settings>
<!--设置mybatis输出日志-->
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
<!--环境配置: 数据库的连接信息
default:必须和某个environment的id值一样。
告诉mybatis使用哪个数据库的连接信息。也就是访问哪个数据库
-->
<environments default="test01">
<!-- environment : 一个数据库信息的配置, 环境
id:一个唯一值,自定义,表示环境的名称。
-->
<environment id="test01">
<!--
transactionManager :mybatis的事务类型
type: JDBC(表示使用jdbc中的Connection对象的commit,rollback做事务处理)
-->
<transactionManager type="JDBC"/>
<!--
dataSource:表示数据源,连接数据库的
type:表示数据源的类型, POOLED表示使用连接池
-->
<dataSource type="POOLED">
<!--
driver, user, username, password 是固定的,不能自定义。
-->
<!--数据库的驱动类名-->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<!--连接数据库的url字符串-->
<property name="url" value="jdbc:mysql://localhost:3306/mybatis01"/>
<!--访问数据库的用户名-->
<property name="username" value="root"/>
<!--密码-->
<property name="password" value="123456"/>
</dataSource>
</environment>
<!--表示线上的数据库,是项目真实使用的库-->
<environment id="online">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/online"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!-- sql mapper(sql映射文件)的位置-->
<mappers>
<!--一个mapper标签指定一个文件的位置。
从类路径开始的路径信息。 target/classes(类路径)
-->
<mapper resource="com/jjh/dao/StudentDao.xml"/>
<!--<mapper resource="com/jjh/dao/SchoolDao.xml" />-->
</mappers>
</configuration>
1.6 创建测试类MyBatisTest
public class App {
public static void main(String[] args) throws IOException {
//访问mybatis读取student数据
//1.定义mybatis主配置文件的名称, 从类路径的根开始(target/classes)
String config="mybatis.xml";
//2.读取这个config表示的文件
InputStream in = Resources.getResourceAsStream(config);
//3.创建了SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//4.创建SqlSessionFactory对象
SqlSessionFactory factory = builder.build(in);
//5.获取SqlSession对象,从SqlSessionFactory中获取SqlSession
SqlSession sqlSession = factory.openSession();
//6.【重要】指定要执行的sql语句的标识。 sql映射文件中的namespace + "." + 标签的id值
//String sqlId = "com.jjh.dao.StudentDao" + "." + "ListAll";
String sqlId = "com.jjh.dao.StudentDao.ListAll";
//7.执行sql语句,通过sqlId找到语句
List<Student> StudentList = sqlSession.selectList(sqlId);
//8.输出结果
StudentList.forEach(student -> System.out.println(student));
//9.关闭SqlSession对象
sqlSession.close();
}
}
二、MyBatis查询基本操作
在查询操作上加以改进
2.1 接口中添加查询方法
- Student添加查询方法
public interface StudentDao {
//查询student表中所有的数据
public List<Student> ListAll();
//插入一条记录
public Integer InsertOne();
}
2.2 修改映射文件
<insert id="insertOne">
insert into student values (#{id},#{name},#{email},#{age});
</insert>
2.3 测试类
public class App2 {
public static void main(String[] args) throws IOException {
//访问mybatis读取student数据
//1.定义mybatis主配置文件的名称, 从类路径的根开始(target/classes)
String config="mybatis.xml";
//2.读取这个config表示的文件
InputStream in = Resources.getResourceAsStream(config);
//3.创建了SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//4.创建SqlSessionFactory对象
SqlSessionFactory factory = builder.build(in);
//5.获取SqlSession对象,从SqlSessionFactory中获取SqlSession
SqlSession sqlSession = factory.openSession();
//6.【重要】指定要执行的sql语句的标识。 sql映射文件中的namespace + "." + 标签的id值
//String sqlId = "com.jjh.dao.StudentDao" + "." + "ListAll";
String sqlId = "com.jjh.dao.StudentDao.insertOne";
//7.执行sql语句,通过sqlId找到语句
Student stu = new Student();
stu.setId(1005);
stu.setName("Lucy");
stu.setEmail("Lucy@gmai.com");
stu.setAge(20);
int result = sqlSession.insert(sqlId,stu);
//mybatis默认不是自动提交事务的, 所以在insert ,update ,delete后要手工提交事务
// sqlSession.commit();
//8.输出结果
System.out.println(result);
//9.关闭SqlSession对象
sqlSession.close();
}
}
2.4 封装MyBatis工具类
public class MyBatisUtils {
private static SqlSessionFactory sqlSessionFactory = null;
static {
String config = "mybatis.xml";
try {
InputStream in = Resources.getResourceAsStream(config);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
} catch (IOException e) {
e.printStackTrace();
}
}
//获取SqlSession的方法
public static SqlSession getSqlSession(){
SqlSession sqlSession = null;
if (sqlSessionFactory != null){
sqlSession = sqlSessionFactory.openSession();//需要手动提交事务
}
return sqlSession;
}
}
三、MyBatis对象分析
3.1 Resources 类
Resources 类,顾名思义就是资源,用于读取资源文件。其有很多方法通过加载并解析资源文件,返回不同类型的 IO 流对象
3.2 SqlSessionFactoryBuilder 类
- SqlSessionFactory 的创建 ,需要使SqlSessionFactoryBuilder 对 象 的 build() 方 法
- 由 于SqlSessionFactoryBuilder 对象在创建完工厂对象后,就完成了其历史使命,即可被销毁
- 所以,一般会将该SqlSessionFactoryBuilder对象创建为一个方法内的局部对象,方法结束,对象销毁
3.3 SqlSessionFactory 接口
- SqlSessionFactory 接口对象是一个重量级对象(系统开销大的对象),是线程安全的,所以一个应用只需要一个该对象即可
- 创建 SqlSession 需要使用 SqlSessionFactory 接口的openSession()方法:
openSession(true):创建一个有自动提交功能的 SqlSession
openSession(false):创建一个非自动提交功能的 SqlSession,需手动提交
openSession():同 openSession(false)
3.4 SqlSession 接口
- SqlSession 接口对象用于执行持久化操作
- 一个 SqlSession 对应着一次数据库会话,一次会话以SqlSession 对象的创建开始,以 SqlSession 对象的关闭结束
- SqlSession 接口对象是线程不安全的,所以每次数据库会话结束前,需要马上调用其 close()方法,将其关闭
- 再次需要会话,再次创建。 SqlSession 在方法内部创建,使用完毕后关闭
四、MyBatis使用传统Dao的开发方式
4.1 操作步骤
- 创建Dao接口
public interface StudentDao {
List<Student> selectStudent();
}
- 创建接口的映射文件
<mapper namespace="com.jjh.dao.StudentDao">
<select id="selectStudent" resultType="com.jjh.domain.dto.Student">
select * from student order by id;
</select>
</mapper>
- 在实现类中实现接口中的方法
public class StudentDaoImpl implements StudentDao {
@Override
public List<Student> selectStudent() {
SqlSession sqlSession = MyBatisUtils.getSqlSession();
String sqlId = "com.jjh.dao.StudentDao.selectStudent";
List<Student> studentList = sqlSession.selectList(sqlId);
sqlSession.close();
return studentList;
}
}
- 在测试类中调用
@Test
public void MyBatis01(){
StudentDao stuDao = new StudentDaoImpl();
List<Student> studentList = stuDao.selectStudent();
studentList.forEach(student -> {
System.out.println(student);
});
}
五、MyBatis 框架 Dao 代理
5.1 操作步骤
- 去掉Dao实现类对象
- getMapper 获取代理对象
@Test
public void MyBatis01(){
/**
* 使用mybatis的动态代理机制, 使用SqlSession.getMapper(dao接口)
* getMapper能获取StudentDao接口对于的实现类对象。
*/
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
//调用mapper方法,执行数据库操作
List<Student> studentList = mapper.selectStudent();
studentList.forEach(stu->{
System.out.println(stu);
});
}
@Test
public void MyBatis02(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
Student student = new Student();
student.setId(1007);
student.setName("张大爷");
student.setEmail("uncleZhang@qq.com");
student.setAge(220);
int result = mapper.insertOne(student);
if (result > 0 ){
//手动提交事务!
sqlSession.commit();
System.out.println("插入成功!!!");
}
}
5.2 原理分析
- StudentDao.xml
parameterType :写在mapper文件中的 一个属性。表示dao接口中方法的参数的数据类型 , 写不写都行
<select id="selectStudentById" parameterType="int" resultType="com.jjh.domain.Student">
select id,name, email,age from student where id=${studentId}
</select>
- 测试类
@Test
public void testSelectStudentById(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
Student student = dao.selectStudentById(1001);
System.out.println("student="+student);
}
1.底层使用动态代理 , 使用SqlSession.getMapper(dao接口.class) 获取这个dao接口的对象
2.从java代码中把数据传入到mapper文件的sql语句中
- 底层jdbc实现的方式
使用#{}之后, mybatis执行sql是使用的jdbc中的PreparedStatement对象
由mybatis执行下面的代码:
1. mybatis创建Connection , PreparedStatement对象
String sql="select id,name, email,age from student where id=?";
PreparedStatement pst = conn.preparedStatement(sql);
pst.setInt(1,1001);
2. 执行sql封装为resultType="com.bjpowernode.domain.Student"这个对象
ResultSet rs = ps.executeQuery();
Student student = null;
while(rs.next()){
//从数据库取表的一行数据, 存到一个java对象属性中
student = new Student();
student.setId(rs.getInt("id));
student.setName(rs.getString("name"));
student.setEmail(rs.getString("email"));
student.setAge(rs.getInt("age"));
}
return student; //给了dao方法调用的返回值
六、MyBatis多个参数的传递
6.1 使用@Param(重点)
- 当 Dao 接口方法多个参数,需要通过名称使用参数。在方法形参前面加入
@Param(“自定义参数名”),mapper 文件使用#{自定义参数名}
- 例如:
List<Student> selectStudent( @Param(“personName”) String name ) { … }
mapper 文件 select * from student where name = #{ personName}
- StudentDao类
//多个参数的查询操作
List<Student> selectMultipleParam(@Param("myName") String name, @Param("myAge") Integer age);
- 映射文件
<select id="selectMultipleParam" resultType="com.jjh.domain.dto.Student">
select * from student where name=#{myName} or age=#{myAge};
</select>
- 测试类
public void Mybatis03(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
List<Student> studentList = mapper.selectMultipleParam("张大爷", 20);
studentList.forEach(stu->{
System.out.println(stu);
});
sqlSession.close();
}
6.2 使用对象(重点)
使用 java 对象传递参数, java 的属性值就是 sql 需要的参数值。 每一个属性就是一个参数
- 语法格式:
#{ property,javaType=java 中数据类型名,jdbcType=数据类型名称 }
javaType, jdbcType 的类型 MyBatis 可以检测出来,一般不需要设置。常用格式
#{ property }
- 创建传递参数的对象
@Data
@AllArgsConstructor
@NoArgsConstructor
public class QueryParam {
private String name;
private Integer age;
}
- Dao接口
//对象多为参数传值
List<Student> selectMultipleObject(QueryParam queryParam);
- 映射文件
<!-- <select id="selectMultiObject" resultType="com.jjh.domain.Student">
select id,name, email,age from student where
name=#{paramName,javaType=java.lang.String,jdbcType=VARCHAR}
or age=#{paramAge,javaType=java.lang.Integer,jdbcType=INTEGER}
</select>-->
<select id="selectMultipleObject" resultType="com.jjh.domain.dto.Student">
select * from student where name=#{name} or age=#{age}
</select>
- 测试类
@Test
public void Mybatis04(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
QueryParam queryParam = new QueryParam();
queryParam.setName("张大爷");
queryParam.setAge(20);
List<Student> studentList = mapper.selectMultipleObject(queryParam);
studentList.forEach(stu->{
System.out.println(stu);
});
sqlSession.close();
}
6.3 使用位置传参
- Dao文件
/**
* 多个参数-简单类型的,按位置传值,
* mybatis.3.4之前,使用 #{0} ,#{1}
* mybatis。3.4之后 ,使用 #{arg0} ,#{arg1}
*/
List<Student> selectMultiPosition( String name,Integer age);
- 映射文件
<!--多个参数使用位置-->
<select id="selectMultiPosition" resultType="com.jjh.domain.Student">
select id,name, email,age from student where
name = #{arg0} or age=#{arg1}
</select>
- 测试类
@Test
public void testSelectMultiPosition(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
List<Student> students = dao.selectMultiPosition("李四",20);
for(Student stu: students){
System.out.println("学生="+stu);
}
sqlSession.close();
}
6.5 使用map传值
- Map 集合可以存储多个值,使用Map向 mapper 文件一次传入多个参数
- Map 集合使用 String的 key,Object 类型的值存储参数 mapper 文件使用
# { key }
引用参数值
6.6 #和$
1.#:占位符
- 告诉 mybatis 使用实际的参数值代替。并使用 PrepareStatement 对象执行 sql 语句
- #{…}代替sql 语句的“?”。这样做更安全,更迅速,通常也是首选做法
- mapper文件
<select id="selectById" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where id=#{studentId}
</select>
- 转换为MyBatis的执行
String sql=” select id,name,email,age from student where id=?”;
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1,1005);
2.$ 字符串替换
告诉 mybatis 使用$包含的“字符串”替换所在位置。使用 Statement 把 sql 语句和${}的内容连接起来
- 主要用在替换表名,列名,不同列排序等操作
七、封装MyBatis的输出结果
7.1 resultType
- resultType: 执行 sql 得到 ResultSet 转换的类型,使用类型的完全限定名或别名
- 注意如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身
- resultType 和 resultMap,不能同时使用。
7.1.1 简单类型
- 接口方法
int countStudent();
- mapper文件
resultType可以使用mybatis内置的别名
mapper 文件:
<select id="countStudent" resultType="int">
select count(*) from student
</select>
- 测试方法
@Test
public void testRetunInt(){
int count = studentDao.countStudent();
System.out.println("学生总人数:"+ count);
}
7.1.2 对象类型
1.执行过程分析:
- mybatis执行了sql语句,得到java对象
- resultType结果类型, 指sql语句执行完毕后,数据转为的java对象, java类型是任意的
- resultType结果类型和值:
- 类型的全限定名称
- 类型的别名,例如:
java.lang.Integer别名是int
<select id="selectMultiPosition" resultType="com.bjpowernode.domain.Student"> select id,name, email,age from student </select>
- 等同于jdbc:
ResultSet rs = executeQuery(" select id,name, email,age from student" ) while(rs.next()){ Student student = new Student(); student.setId(rs.getInt("id")); student.setName(rs.getString("name")) }
2.定义自定义类型的别名:
- 在mybatis主配置文件中定义,使
<typeAlias>
定义别名- 可以在resultType中使用自定义别名
- 接口方法
ViewStudent selectByViewStudent(ViewStudent vs);
- 全局配置别名
<!--
第一种方式:
可以指定一个类型一个自定义别名
type:自定义类型的全限定名称
alias:别名(短小,容易记忆的)
-->
<!--<typeAlias type="com.jjh.domain.Student" alias="stu" />
<typeAlias type="com.jjh.vo.ViewStudent" alias="vstu" />-->
<!--
第二种方式
<package> name是包名, 这个包中的所有类,类名就是别名(类名不区分大小写)
-->
<typeAliases>
<package name="com.jjh.domain"/>
<package name="com.jjh.domain.dto"/>
</typeAliases>
- mapper文件
<select id="selectByViewStudent" resultType="com.jjh.domain.dto.ViewStudent">
select id,name from student where id=#{id};
</select>
- 测试类
@Test
public void MyBatis05(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
ViewStudent vs = new ViewStudent();
vs.setId(1005);
ViewStudent viewStudent = mapper.selectByViewStudent(vs);
System.out.println(viewStudent);
}
7.2 resultMap
7.2.1 传统方式使用map作为返回类型
- dao接口方法
List<Map<Object,Object>> selectByIdReturnMap(Integer id);
- mapper文件
<select id="selectByIdReturnMap" resultType="java.util.HashMap">
select * from student where id>#{id};
</select>
- 测试类
@Test
public void MyBatis05(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
List<Map<Object, Object>> maps = mapper.selectByIdReturnMap(1001);
maps.stream().forEach(map->{
System.out.println(map);
});
sqlSession.close();
}
7.2.1 resultMap概述
- resultMap 可以自定义 sql 的结果和 java 对象属性的映射关系。更灵活的把列值赋值给指定属性
- 常用在列名和 java 对象属性名不一样的情况
7.2.3 resultMap操作步骤
1.先定义 resultMap,指定列名和属性的对应关系
2.==在<select>
中把 resultType 替换为 resultMap
- MyStudent实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class MyStudent {
private Integer stuId;
private String stuName;
private String stuEmail;
private Integer stuAge;
}
- Dao接口
List<MyStudent> selectMyStudent ();
- mapper文件
<!--
定义resultMap
id:自定义名称,表示你定义的这个resultMap
type:java类型的全限定名称
-->
<resultMap id="myStudentMap" type="com.jjh.domain.dto.MyStudent">
<!--列名和java属性的关系-->
<!--注解列,使用id标签
column :列名
property:java类型的属性名
-->
<id column="id" property="stuId"/>
<!--非主键列,使用result-->
<result column="name" property="stuName"/>
<result column="age" property="stuAge"/>
<result column="email" property="stuEmail"/>
</resultMap>
<!--查询语句-->
<select id="selectMyStudent" resultMap="myStudentMap">
select * from student;
</select>
- 测试类
@Test
public void MyBatisMap(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
List<MyStudent> myStudents = mapper.selectMyStudent();
myStudents.forEach(stu->{
System.out.println(stu);
});
sqlSession.close();
}
7.2.4 实体类属性名和列名不同的处理方式
1.使用列别名和<resultType>
在mapper文件编辑sql语句时给属性名起别名
List<PrimaryStudent> selectUseFieldAlias(QueryParam param);
<select id="selectUseFieldAlias"
resultType="com.bjpowernode.domain.PrimaryStudent">
select id as stuId, name as stuName,age as stuAge
from student where name=#{queryName} or age=#{queryAge}
</select>
2.使用<resultMap>
List<PrimaryStudent> selectUseDiffResultMap(QueryParam param);
<!-- 创建 resultMap
id:自定义的唯一名称,在<select>使用
type:期望转为的 java 对象的全限定名称或别名
--> <resultMap id="primaryStudentMap"
type="com.jjh.domain.PrimaryStudent">
<!-- 主键字段使用 id -->
<id column="id" property="stuId" />
<!--非主键字段使用 result-->
<result column="name" property="stuName"/>
<result column="age" property="stuAge" />
</resultMap>
<!--resultMap: resultMap 标签中的 id 属性值--> <select id="selectUseDiffResultMap" resultMap="primaryStudentMap">
select id,name,email,age from student
where name=#{queryName} or age=#{queryAge}
</select>
7.3 模糊查询like
需求:查询带有“大”的数据
- Dao接口
//模糊查询
Student selectLikeOne(String name);
- mapper文件
<!--模糊查询-->
<select id="selectLikeOne" resultType="com.jjh.domain.dto.Student">
select * from student where name like "%" #{stuName} "%"
</select>
- 测试类
@Test
public void MyBatisLike(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
String name = "大";
Student student = mapper.selectLikeOne(name);
System.out.println(student);
sqlSession.close();
}
八、动态SQL
8.1 动态sql之<if>
- 对于该标签的执行,当 test 的值为 true 时,会将其包含的 SQL 片断拼接到其所在的 SQL 语句中
- 语法:
<if test=”条件”> sql 语句的部分 </if>
- Dao接口
public interface StudentDao {
List<Student> selectIf(Student condition);
}
- mapper文件
<select id="selectIf" resultType="com.jjh.domain.dto.Student">
select * from student
where 1=1
<if test="name != null and name != ''">
name = #{name}
</if>
<if test="age > 0">
or age > #{age}
</if>
</select>
- 测试类
@org.junit.Test
public void demo01(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
//使用对象传递参数
Student stu = new Student();
stu.setAge(19);
stu.setName("张大爷");
List<Student> studentList = mapper.selectIf(stu);
studentList.forEach(student -> {
System.out.println(student);
});
sqlSession.close();
}
<if>
不足之处:
<if/>
标签的中存在一个比较麻烦的地方:需要在 where 后手工添加 1=1 的子句- 若 where 后的所有
<if/>
条件均为 false,而 where 后若又没有 1=1 子句,则 SQL 中就会只剩下一个空的 where,SQL会出错- 所以,在 where 后,需要添加永为真子句 1=1,以防止这种情况的发生。但当数据量很大时,会严重影响查询效率
8.2 动态 SQL 之<where>
- 使用
<where/>
标签,在有查询条件时,可以自动添加上 where 子句- 没有查询条件时,不会添加where 子句
- 需要注意的是,第一个
<if/>
标签中的 SQL 片断,可以不包含 and- 但其它
<if/>
中 SQL 片断的 and,必须要求写上。否则 SQL 语句将拼接出错
- Dao接口
List<Student> selectWhereIf(Student condition);
- mapper文件
<select id="selectWhereIf" resultType="com.jjh.domain.dto.Student">
select * from student
<where>
<if test="name != null and name != ''">
name=#{name}
</if>
<if test="age > 0">
and age>#{age}
</if>
</where>
</select>
- 测试类
@org.junit.Test
public void demo02(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
Student stu = new Student();
// stu.setName("王麻子");
stu.setAge(19);
List<Student> studentList = mapper.selectWhereIf(stu);
studentList.forEach(student->{
System.out.println(student);
});
sqlSession.close();
}
8.3 动态 SQL 之<foreach>
1.
<foreach/>
标签用于实现对于数组与集合的遍历
- collection 表示要遍历的集合类型, list ,array 等
- open、close、separator 为对遍历内容的 SQL 拼接
2.
<foreach/>
标签的属性及其作用:
- collection:表示接口中的方法参数的类型, 如果是数组使用array , 如果是list集合使用list
- item:自定义的,表示数组和集合成员的变量
- open:循环开始是的字符
- separator:集合成员之间的分隔符
8.2.1 遍历 List<简单类型>
- Dao接口
List<Student> selectStudentForEach(List<Integer> idList);
- mapper文件
<select id="selectStudentForEach" resultType="com.jjh.domain.dto.Student">
select * from student
where id in
<foreach collection="list" item="myId" open="(" close=")" separator=",">
#{myId}
</foreach>
</select>
- 测试类
@org.junit.Test
public void demo03(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
List<Integer> list = new ArrayList<>();
list.add(1001);
list.add(1002);
list.add(1003);
List<Student> studentList = mapper.selectStudentForEach(list);
studentList.forEach(stu->{
System.out.println(stu);
});
sqlSession.close();
}
8.2.2 遍历 List<对象类型>
- Dao接口
List<Student> selectStudentForEach2(List<Student> stuList);
- mapper文件
<select id="selectStudentForEach2" resultType="com.jjh.domain.dto.Student">
select * from student
where id in
<foreach collection="list" item="stu" open="(" close=")" separator=",">
#{stu.id}
</foreach>
</select>
- 测试类
@org.junit.Test
public void demo04(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
List<Student> stuList = new ArrayList<>();
Student s1 = new Student();
s1.setId(1005);
stuList.add(s1);
s1 = new Student();
s1.setId(1002);
stuList.add(s1);
List<Student> studentList = mapper.selectStudentForEach2(stuList);
studentList.forEach(stu->{
System.out.println(stu);
});
sqlSession.close();
}
8.4 动态 SQL 之代码片段
<sql/>
标签用于定义 SQL 片断,以便其它 SQL 标签复用。而其它标签使用该 SQL 片断,需要使用<include/>
子标签- 该
<sql/>
标签可以定义 SQL 语句中的任何部分,所以<include/>
子标签可以放在动态 SQL的任何位置。
- Dao接口
List<Student> selectStudentSqlFragment(List<Student> stuList);
- mapper文件
<!--创建 sql 片段 id:片段的自定义名称-->
<sql id="studentSql">
select id,name,email,age from student
</sql>
<select id="selectStudentSqlFragment"
resultType="com.jjh.domain.Student">
<!-- 引用 sql 片段 -->
<include refid="studentSql"/>
<if test="list !=null and list.size > 0 ">
where id in
<foreach collection="list" open="(" close=")"
item="stuobject" separator=",">
#{stuobject.id}
</foreach>
</if>
</select>
九、MyBatis配置文件
- mybatis.xml
<?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>
<!--指定properties文件的位置,从类路径根开始找文件-->
<properties resource="jdbc.properties" />
<!--settings:控制mybatis全局行为-->
<settings>
<!--设置mybatis输出日志-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!--定义别名-->
<typeAliases>
<!--
第一种方式:
可以指定一个类型一个自定义别名
type:自定义类型的全限定名称
alias:别名(短小,容易记忆的)
-->
<!--<typeAlias type="com.bjpowernode.domain.Student" alias="stu" />
<typeAlias type="com.bjpowernode.vo.ViewStudent" alias="vstu" />-->
<!--
第二种方式
<package> name是包名, 这个包中的所有类,类名就是别名(类名不区分大小写)
-->
<package name="com.bjpowernode.domain"/>
<package name="com.bjpowernode.vo"/>
</typeAliases>
<!--配置插件-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor" />
</plugins>
<environments default="mydev">
<environment id="mydev">
<!--
transactionManager:mybatis提交事务,回顾事务的方式
type: 事务的处理的类型
1)JDBC : 表示mybatis底层是调用JDBC中的Connection对象的,commit, rollback
2)MANAGED : 把mybatis的事务处理委托给其它的容器(一个服务器软件,一个框架(spring))
-->
<transactionManager type="JDBC"/>
<!--
dataSource:表示数据源,java体系中,规定实现了javax.sql.DataSource接口的都是数据源。
数据源表示Connection对象的。
type:指定数据源的类型
1)POOLED: 使用连接池, mybatis会创建PooledDataSource类
2)UPOOLED: 不使用连接池, 在每次执行sql语句,先创建连接,执行sql,在关闭连接
mybatis会创建一个UnPooledDataSource,管理Connection对象的使用
3)JNDI:java命名和目录服务(windows注册表)
-->
<dataSource type="POOLED">
<!--数据库的驱动类名-->
<property name="driver" value="${jdbc.driver}"/>
<!--连接数据库的url字符串-->
<property name="url" value="${jdbc.url}"/>
<!--访问数据库的用户名-->
<property name="username" value="${jdbc.user}"/>
<!--密码-->
<property name="password" value="${jdbc.passwd}"/>
</dataSource>
</environment>
</environments>
<!-- sql mapper(sql映射文件)的位置-->
<mappers>
<!--第一种方式:指定多个mapper文件-->
<!--<mapper resource="com/bjpowernode/dao/StudentDao.xml"/>
<mapper resource="com/bjpowernode/dao/OrderDao.xml" />-->
<!--第二种方式: 使用包名
name: xml文件(mapper文件)所在的包名, 这个包中所有xml文件一次都能加载给mybatis
使用package的要求:
1. mapper文件名称需要和接口名称一样, 区分大小写的一样
2. mapper文件和dao接口需要在同一目录
-->
<package name="com.bjpowernode.dao"/>
<!-- <package name="com.bjpowernode.dao2"/>
<package name="com.bjpowernode.dao3"/>-->
</mappers>
</configuration>
9.1 使用数据库属性配置文件
为了方便对数据库连接的管理,DB 连接四要素数据一般都是存放在一个专门的属性文件中的。MyBatis主配置文件需要从这个属性文件中读取这些数据
1.在 classpath 路径下创建properties文件
2.使用 properties 标签
3.使用 key 指定值