文章目录
MyBatis学习笔记
1、MyBatis相关概念:
基本概念:
前身:MyBatis 本是apache的一个开源项目iBatis 。未来我们编写代码的时候,导入包的时候可以看到很多ibatis的包,就是我们的MyBatis。
MyBatis源码:需要在 Github 上下载!
官网地址:https://mybatis.org/mybatis-3/
什么是“持久化” ?
- 持久(Persistence),即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)。持久化的主要应用是将内存中的数据存储在关系型的数据库中,当然也可以存储在磁盘文件中、XML数据文件中等等。
什么是 “持久层” ?
- 持久层(Persistence Layer),即专注于实现数据持久化应用领域的某个特定系统的一个逻辑层面,将数据使用者和数据实体相关联
MyBatis 的特性:
- MyBatis 是一款优秀的持久层框架
- 它支持定制化 SQL、存储过程以及高级映射。
- MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
- MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
问题:MyBatis 是如何读取配置文件进行加载的?运行原理是什么
个人见解:
- 我们在MyBatis中经常需要把一条记录抽象为一个具体的对象。
- 光通过在MyBatis上配置就可以获得数据库的查询结果,其实就跟我们写的JDBC工具类一样,只不过它更为高级和简化一些。
- 如果MyBatis只到这种程度,估计还算不上特别大的功能,这些抽象到最后可能会被进一步封装,最后能让我们实现所谓的ORM。
- ORM:Object-Relationl Mapping,它的作用是在关系型数据库和对象之间作一个映射,这样,我们在具体的操作数据库的时候,就不需要再去和复杂的SQL语句打交道,只要像平时操作对象一样操作它就可以了(不再需要编写SQL语句了,直接用这个对象即可)。
2、MyBatis 使用案例:
实验过程:
```mermaid
st=>start: 搭建环境
op=>operation: 导入包
op2=>operation: 写代码
e=>end: 测试
st->op->op2->e->
```
1、准备一个数据库:
1、 CREATE DATABASE `mybatis`;
2、USE `mybatis`;
3、CREATE TABLE `user`(
`id` INT(20) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
`pwd` VARCHAR(30) DEFAULT NULL,
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO `user`(`id`,`name`,`pwd`)
VALUES (1,'周丹','123456'),(2,'周颖','zxcvbn'),(3,'姜嘉航','123456');
2、准备相关jar包的依赖:(在Maven 仓库中查询的结果)
1)先创建一个空的Maven项目(模板:无)
2)在pom.xml中的相应位置添加依赖:
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
3、编写配置文件:resources/mybatis-config.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>
<setting name="logImpl" value="NO_LOGGING"/>
</settings>
<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/mybatis?
useSSL=true&useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!--mappers 中配置的是需要解析.xml文件-->
<mappers>
</mappers>
</configuration>
4、编写一个工具类来操作数据库:(目的是为了获取SqlSession对象)
在 main/java 下新建一个包:edu.nwu.utils,创建 MybatisUtils类:
package edu.nwu.utils;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
// 工厂模式:
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}catch (IOException e){
e.printStackTrace();
}
}
// 获取sqlSession的连接:
public static SqlSession getSession(){
return sqlSessionFactory.openSession();
}
}
5、配置了一个实体类,引入了Lombok
LomBok概念:
- 以前的Java项目中,充斥着太多不友好的代码:
- POJO的getter/setter/toString;异常处理;I/O流的关闭操作等等,这些样板代码既没有技术含量,又影响着代码的美观
- Lombok就是为了解决这些问题应运而生,使用注解来代替这些重复的代码,简化开发流程。
LomBok相关依赖:
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
<scope>provided</scope>
</dependency>
在 main/java 下创建一个包:edu.nwu.pojo 创建文件类:User
package edu.nwu.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;
private String name;
private String pwd;
}
6、持久层的操作接口:(MyBatis的规则)
在 main/java 下 创建:edu.nwu.mapper包,创建 UserMapper映射类:
package edu.nwu.mapper;
import com.kuang.pojo.User;
import java.util.List;
// 操作用户的接口类(这里可以写多个实现方法)
public interface UserMapper {
List<User> getUserList();
User selectById(int id);
}
7、本来我们需要编写接口的实现类,使用了MyBatis之后,我们可以专注写SQL来配置文件。
在resources 目录下:创建于刚才映射接口同级的包:edu.nwu.mapper,创建UserMapper.xml(文件名也是同步映射过来的,知不是转为了.xml文件)
这样做的好处:
- 当程序运行起来以后,我们依旧可以动态的修改代码。
- 假设这个.java文件是放到Web应用程序下的,每一次启动服务器后,这些代码就被编译成.class 文件,用于执行逻辑。如果代码发生的话,想要生效必须重新编译生成新的.class文件。
- 但在Mybatis中,我们由于这些SQL执行逻辑都写在配置文件中,而不是代码中,所以我们可以动态地修改代码,这起到了程序解耦的作用。
与相关接口对应的.xml配置文件的写法:
- namespace 绑定对应的接口,
- 标签和操作相对应:查询 => select , 添加 => insert , 更新 => update ,删除 => delete
- 具体操作(CRUD)中的 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="edu.nwu.mapper.UserMapper">
<!-- 原来我们都是编写具体的执行SQL,这里可以引入一些参数写法都是:#{数据库/对象字段名} -->
<select id="getUserList" resultType="edu.nwu.pojo.User">
select * from user;
</select>
<select id="selectById" resultType="edu.nwu.pojo.User">
select * from user where id = #{id};
</select>
</mapper>
8、这个配置文件一定要注册到Mybatis的配置文件(resources/mybatis-config.xml)中(重要)
<mapper resource="edu/nwu/mapper/UserMapper.xml"/>
9、编写测试类运行:
在test/java 下创建 Test 测试类:
import edu.nwu.mapper.UserMapper;
import edu.nwu.mapper.UserMapperX;
import edu.nwu.pojo.User;
import edu.nwu.pojo.UserX;
import edu.nwu.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;
public class Test {
static Logger logger = Logger.getLogger(Test.class);
public static void main(String[] args) {
selectById();
System.out.println("=========");
selectAll();
}
public static void selectById(){
// 1、 获取SqlSession, 执行sql使用的
SqlSession session = MybatisUtils.getSession();
// 2、通过 session.getMapper(Class ) 获得接口
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.selectById(1);
System.out.println(user);
}
public static void selectAll(){
// 1、 获取SqlSession, 执行sql使用的
SqlSession session = MybatisUtils.getSession();
// 2、通过 session.getMapper(Class ) 获得接口
UserMapper mapper = session.getMapper(UserMapper.class);
List<User> userList = mapper.getUserList();
for (User user : userList) {
System.out.println(user);
}
}
}
------------
结果:
User(id=1, name=周丹, pwd=123456)
=========
User(id=1, name=周丹, pwd=123456)
User(id=2, name=周颖, pwd=1asdfasd)
User(id=3, name=小波, pwd=1ssssfasd)
3、CRUD 增删改查:
固话的操作流程:
1、编写(新/旧)接口中的方法;
2、编写接口对应的SQL配置文件(一定要确保配置文件的SQL的正确性)
3、编写测试类进行测试:
需要注意的点:
1、多个参数一定要增加 @Param 注解
2、增删改一定要增加事务提交
3、在.xml中的增删改,标签一定要写对应,传入的参数类型必须要写。*
4、在*.xml中的增, 标签一定也要写对应,传出参数类型必须要写。
5、增删改不用写返回值,查询必须写返回值,注意:是集合、泛型中的内容(具体的某个对象的类型)
代码案例:
1、通过id 查询用户 User selectById(int id);
2、通过用户名和密码查询用户 User selectByUsernamePwd(String username, String pwd);
3、新增一个用户 int addUser(User user);
4、修改用户信息 int updateUser(User user);
5、删除一个用户 int deleteUserByID(int id);
- 更改接口类:
package edu.nwu.mapper;
import edu.nwu.pojo.User;
import org.apache.ibatis.annotations.Param;
import java.util.List;
// 操作用户的接口类
public interface UserMapper {
List<User> getUserList();
User selectById(int id);
User selectByUsernamePwd(@Param("username") String username, @Param("pwd") String pwd);
// 添加一个用户的方法:
int addUser(User user);
// 删除一个用户的方法:
int deleteUser(User user);
// 更新一个用户记录的方法:(这个返回值的意义是:有几条记录参与修改成功)
int updateUser(User user);
}
- 更改接口类所对应的.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="edu.nwu.mapper.UserMapper">
<select id="getUserList" resultType="edu.nwu.pojo.User">
select * from user;
</select>
<select id="selectById" resultType="edu.nwu.pojo.User">
select * from user where id = #{id};
</select>
<select id="selectByUsernamePwd" resultType="edu.nwu.pojo.User">
select * from user where name = #{username} and pwd= #{pwd};
</select>
<insert id="addUser" parameterType="edu.nwu.pojo.User">
insert into `user`(`id`,`name`,`pwd`) values (#{id},#{name},#{pwd});
</insert>
<delete id="deleteUser" parameterType="edu.nwu.pojo.User">
delete from `user` where id=#{id} and name=#{name} and pwd = #{pwd} ;
</delete>
<update id="updateUser" parameterType="edu.nwu.pojo.User">
update `user` set name=#{name},pwd=#{pwd} where id=#{id};
</update>
</mapper>
- 注册到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>
<settings>
<setting name="logImpl" value="NO_LOGGING"/>
</settings>
<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/mybatis?
useSSL=true&useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="edu/nwu/mapper/UserMapper.xml"/>
<mapper
</mappers>
</configuration>
- 编写测试类:
import edu.nwu.mapper.UserMapper;
import edu.nwu.mapper.UserMapperX;
import edu.nwu.pojo.User;
import edu.nwu.pojo.UserX;
import edu.nwu.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;
import java.util.List;
public class Test {
static Logger logger = Logger.getLogger(Test.class);
public static void main(String[] args) {
selectById();
System.out.println("=========");
selectAll();
// insert();
// delete();
// update();
}
public static void select(){
// 1、 获取SqlSession, 执行sql使用的
SqlSession session = MybatisUtils.getSession();
// 2、通过 session.getMapper(Class ) 获得接口
UserMapper mapper = session.getMapper(UserMapper.class);
User user1 = mapper.selectByUsernamePwd("周丹","123456");
System.out.println(user1);
}
public static void selectById(){
// 1、 获取SqlSession, 执行sql使用的
SqlSession session = MybatisUtils.getSession();
// 2、通过 session.getMapper(Class ) 获得接口
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.selectById(1);
System.out.println(user);
}
public static void selectAll(){
// 1、 获取SqlSession, 执行sql使用的
SqlSession session = MybatisUtils.getSession();
// 2、通过 session.getMapper(Class ) 获得接口
UserMapper mapper = session.getMapper(UserMapper.class);
List<User> userList = mapper.getUserList();
for (User user : userList) {
System.out.println(user);
}
}
public static void update(){
// 1、 获取SqlSession, 执行sql使用的
SqlSession session = MybatisUtils.getSession();
// 2、通过 session.getMapper(Class ) 获得接口
UserMapper mapper = session.getMapper(UserMapper.class);
int i = mapper.updateUser(new User(10, "超级可爱的佳露宝", "xuankulanzuan9"));
System.out.println(i);
session.commit();
}
public static void insert(){
// 1、 获取SqlSession, 执行sql使用的
SqlSession session = MybatisUtils.getSession();
// 2、通过 session.getMapper(Class ) 获得接口
UserMapper mapper = session.getMapper(UserMapper.class);
int x = mapper.addUser(new User(5, "佳露宝", "123456"));
System.out.println(x);
session.commit();
}
public static void delete(){
SqlSession session = MybatisUtils.getSession();
UserMapper mapper = session.getMapper(UserMapper.class);
int x = mapper.deleteUser(new User(5, "佳露宝", "123456"));
System.out.println(x);
session.commit();
}
}
注意:
- 增删改方法执行完对应的返回值是int类型的数据,其代表了到底有多少行记录生效了。
- 一般返回1代表1条记录生效。
- 返回0代表0行记录生效,也就是失败!
4、Mybatis 配置文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KKdUe27Z-1582305117228)(/Users/zhengjiaxiang/Desktop/MyBatis/MyBatis.assets/image-20200219144228349.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oY1wDC9l-1582305194393)(/Users/zhengjiaxiang/Desktop/MyBatis/MyBatis.assets/image-20200219144228349.png)]
注意:
- 这些配置项是有顺序的(顺序如图所示)
- 圈红部分为常用重要的配置项
配置db.properties 让配置文件读取数据库的相关信息:
1、编写配置文件,文件位置为:resources/db.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf8
username=root
password=123456
2、在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>
<!--xml 中元素的标签上下位置是有要求的-->
<!-- 将配置文件改为properties -->
<properties resource="db.properties"/>
<!-- 一个environments 标签元素可以有多套配置 -->
<environments default="development">
<!-- 里面的每一个environment代表一个具体的环境 -->
<environment id="development">
<!--transactionManager 事务管理器 -->
<transactionManager type="JDBC"/>
<!-- dataSource 数据源配置 -->
<dataSource type="POOLED">
<!-- 连接数据库的配置i-->
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="edu/nwu/mapper/UserMapper.xml"/>
</mappers>
</configuration>
通过Settings 设置普通日志。
目的:
- 查看系统的启动过程(拍错)
- 可以看到拼接SQL的过程,以此来查看自己的SQL是否转换出错等等
1、更改Mybatis主配置文件:
<settings>
<!--<setting name="logImpl" value="NO_LOGGING"/> 这个是关闭日志的选项-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
2、输出结果查看:
/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/bin/java "-javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=60686:/Applications/IntelliJ IDEA.app/Contents/bin" -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/lib/tools.jar:/Users/zhengjiaxiang/IdeaProjects/Mybatis-Test/target/test-classes:/Users/zhengjiaxiang/IdeaProjects/Mybatis-Test/target/classes:/Users/zhengjiaxiang/Library/maven/maven-repo/org/mybatis/mybatis/3.5.4/mybatis-3.5.4.jar:/Users/zhengjiaxiang/Library/maven/maven-repo/mysql/mysql-connector-java/5.1.47/mysql-connector-java-5.1.47.jar:/Users/zhengjiaxiang/Library/maven/maven-repo/org/projectlombok/lombok/1.18.8/lombok-1.18.8.jar:/Users/zhengjiaxiang/Library/maven/maven-repo/log4j/log4j/1.2.17/log4j-1.2.17.jar Test
[DEBUG] 2020-02-19 22:07:43,305 method:org.apache.ibatis.logging.LogFactory.setImplementation(LogFactory.java:105)
Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.
Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
Opening JDBC Connection
Created connection 1188753216.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@46daef40]
==> Preparing: select * from user where id = ?;
==> Parameters: 1(Integer)
<== Columns: id, name, pwd
<== Row: 1, 周丹, 123456
<== Total: 1
User(id=1, name=周丹, pwd=123456)
=========
Opening JDBC Connection
Created connection 682376643.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@28ac3dc3]
==> Preparing: select * from user;
==> Parameters:
<== Columns: id, name, pwd
<== Row: 1, 周丹, 123456
<== Row: 2, 周颖, 1asdfasd
<== Row: 3, 小波, 1ssssfasd
<== Row: 4, 郑嘉祥, 123456
<== Row: 10, 超级可爱的佳露宝, xuankulanzuan9
<== Total: 5
User(id=1, name=周丹, pwd=123456)
User(id=2, name=周颖, pwd=1asdfasd)
User(id=3, name=小波, pwd=1ssssfasd)
User(id=4, name=郑嘉祥, pwd=123456)
User(id=10, name=超级可爱的佳露宝, pwd=xuankulanzuan9)
通过Settings 设置log4j日志
Log4j:在工作中用的更多,它可以按照级别配置日志的输出与保存等等,功能更为强大!
1、导入相关的依赖:
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
2、在resources目下下,创建:log4j.properties文件:
### 设置###
log4j.rootLogger = debug,stdout,D,E
### 输出信息到控制抬 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
### 输出DEBUG 级别以上的日志到=E://logs/error.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = ./log/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
### 输出ERROR 级别以上的日志到=E://logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =./log/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
3、在Mybatis主配置文件中修改日志选项:
<settings>
<!--<setting name="logImpl" value="NO_LOGGING"/>-->
<!--<setting name="logImpl" value="STDOUT_LOGGING"/>-->
<setting name="logImpl" value="LOG4J"/>
</settings>
4、会自动生成对应的log日志目录(根据log4j.properties所得)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0HkyHtnN-1582305117229)(MyBatis学习笔记.assets/Xnip2020-02-19_22-18-05.jpg)]
5、还能在函数中具体使用它们来代替print
import org.apache.log4j.Logger;
public class Test1 {
// 注意导入包的问题 org.apache.log4j.Logger
static Logger logger = Logger.getLogger(Test1.class);
public static void main(String[] args) {
SqlSession session = MyBatisUtils.getSession();
RMapper mapper = session.getMapper(RMapper.class);
System.out.println("1231321222222");// 普通的输出
// 通过log4j 可以将日志实现细粒度的控制;
logger.error("1231321222222"); // 错误信息
logger.info("1231321222222"); // 提示信息
logger.debug("1231321222222");
}
}
配置类型别名,简化开发
注意:
- 起别名也是在mybayis的配置文件中去配的,在其中去声明
配置文件:
<!--包的别名配置-->
<typeAliases>
<!-- 给包下所有类起别名 -->
<package name="edu.nwu.pojo"/>
<!-- 给一个类起别名 alias是自己起的别名-->
<!--<typeAlias type="edu.nwu.pojo.User" alias="User"/>-->
</typeAliases>
接口所对应的配置文件:(注意上下两者的区别,其了别名以后就可以直接使用User了)
<select id="getUserList" resultType="User">
select * from user;
</select>
<select id="selectById" resultType="edu.nwu.pojo.User">
select * from user where id = #{id};
</select>
配置 mapper 映射器,来扫描一个包下的内容:(常用)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XX63gv4w-1582305117229)(MyBatis学习笔记.assets/image-20200219145755295.png)]
特点:这样的话,即使创建再多的接口,我们也不用没一个都注册到Mybatis主配置文件中去了,只需要把路径对应写好就OK
1、设置主配置文件:
<mappers>
<!--<mapper resource="edu/nwu/mapper/UserMapper.xml"/>-->
<!--<mapper resource="edu/nwu/mapper/UserMapperX.xml"/>-->
<package name="edu.nwu.mapper"/>
</mappers>
2、项目文件结构:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m5d55LZQ-1582305117229)(MyBatis学习笔记.assets/Xnip2020-02-19_22-33-59.jpg)]
5、ResultMap
问题:假如我们定义的类的属性名和数据库字段中的名字不一致!
问题呈现:
下面使我们定义的用户类:
package edu.nwu.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserX {
private int id;
private String name;
private String password;
}
数据相关字段如下:
mysql> desc user;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int(20) | NO | PRI | NULL | |
| name | varchar(30) | YES | | NULL | |
| pwd | varchar(30) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
我们发现:其password和pwd不对应。
注意:如果直接在原类中修改字段属性,可能会造成连锁的反应,不推荐这修改。
接口:
package edu.nwu.mapper;
import edu.nwu.pojo.UserX;
public interface UserMapperX {
UserX selectById(int 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="edu.nwu.mapper.UserMapperX">
<select id="selectById" resultType="UserX">
select * from user where id = #{id};
</select>
</mapper>
这样使用的时候,会造成一种情况:(由于字段不对应造成null值)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F8vVp0tA-1582305117230)(MyBatis学习笔记.assets/Xnip2020-02-19_22-43-36.jpg)]
方法:通过Mapper映射!
1、在接口对应的配置文件中:resources/UserMapperX.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="edu.nwu.mapper.UserMapperX">
<resultMap id="UserMap" type="edu.nwu.pojo.UserX">
<!--这里只需要对不对应的字段进行映射处理即可!-->
<result column="pwd" property="password"/>
</resultMap>
<select id="selectById" resultMap="UserMap">
<!--<select id="selectById" resultType="UserX">-- -->
select * from user where id = #{id};
</select>
</mapper>
执行结果:(null值已经正常!)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uMRG4Gvz-1582305117230)(MyBatis学习笔记.assets/image-20200219224800726.png)]
6、分页(一定要会)
为什么要分页?
目的:提高服务器性能,按照一小部分一小部分来处理我们的数据。
Limit :(语法)
select * from user limit startIndex,Pagesize
在接口中添加函数:(特别注意使用的参数传递方法!)
注意:
- 这里我们使用的是Map来作为SQL配置文件解析的参数,当我们的实体类或者数据库中的表的字段过多时,我们就应当考虑Map了!
- 它算是一种万能的参数传递方法。
Mybatis的Sql方法中能够传递参数的方法:
- Map传递参数,直接在sql中取出即可!
- 对象传递传递参数,直接在sql中取出对象属性即可。(但得构建一个完整的对象)
- 只有一个基本类型参数的情况下,可以直接在sql中取到。
- 多个参数用Map,或者注解
// 带分页的操作
// 参数如果超过两个,可以使用map来进行传递指
// key value
List<User> selectUserByLimit(Map<String,Integer> map);
配置接口对应的文件:
<!-- 非基本类型之外的数据类型,如:List、Map等类型需要显示的定义 -->
<select id="selectUserByLimit" parameterType="map" resultType="User">
select * from user limit #{startIndex},#{pageSize}
</select>
注意:测试类 map 中的key,必须要和 sql 中接收的参数一致。
// 测试分页!
public static void limitTest() {
SqlSession session = MybatisUtils.getSession();
UserMapper mapper = session.getMapper(UserMapper.class);
int currentPage = 2; //第几页
int pageSize = 3; //每页显示几个
HashMap<String, Integer> map = new HashMap<String, Integer>();
// 分页 第几页 每页显示几个
map.put("startIndex", (currentPage - 1) * pageSize);
map.put("pageSize", pageSize);
List<User> users = mapper.selectUserByLimit(map);
for (User user : users) {
logger.debug(user);
}
}
这个只是SQL层面的分层,我们还有在Java层面实现的分层:RowBounds
RowBounds 分页(拓展了解)
扩展 : 分页插件 PageHelper
地址:https://pagehelper.github.io/ 也可通过插件实现分页!
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P7RvePpl-1582305117231)(MyBatis学习笔记.assets/image-20200219164903480.png)]
7、模糊查询:
1、在接口中创建方法:
List<User> getUserLike(String value);
2、在xml文件中添加实现:
<select id="getUserLike" resultType="User">
select * from user where name like #{value};
</select>
3、注册到主配置文件中(我们已经设置了包扫描,所以不用担心这个)
4、编写测试类:
public static void getUserLike(){
SqlSession session = MybatisUtils.getSession();
UserMapper mapper = session.getMapper(UserMapper.class);
List<User> userLike = mapper.getUserLike("郑%");
for (User user : userLike) {
System.out.println(user);
}
}
5、这样写不够安全,用户传进来的数值里存在特殊字符,容易造成安全问题,所以也可以把这种通配的符号写在配置文件中:
<select id="getUserLike" resultType="User">
select * from user where name like "%"#{value}"%";
</select>
8、生命周期和作用域:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jHfJ8M9W-1582305117231)(MyBatis学习笔记.assets/1569660357745.png)]
生命周期,和作用域,是至关重要的,因为错误的使用会导致非常严重的并发问题。
官方参考文档:作用域(Scope)和生命周期中有更为详细的解释!
SqlSessionFactoryBuilder:
- 一旦创建了 SqlSessionFactory,就不再需要它了
- 局部变量
SqlSessionFactory:
- 说白了就是可以想象为 :数据库连接池
- SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。
- 因此 SqlSessionFactory 的最佳作用域是应用作用域。
- 最简单的就是使用单例模式或者静态单例模式。
SqlSession
- 连接到连接池的一个请求!
- SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
- 用完之后需要赶紧关闭,否则资源被占用!
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wWIho2pF-1582305117231)(MyBatis学习笔记.assets/1569660737088.png)]
这里面的每一个Mapper,就代表一个具体的业务!
9、工厂模式
参考:狂神的Java视频所述
10. Mybatis 进阶(一对多、多对一)
概念:
在多对一的案例中:多个学生对应一个老师,此时的个体是老师(即:老师类中不会存在包含其他类对象属性),学生和老师之间的关系是:“关联”,即:每个学生都可以关联一个老师。(关联代指一个对象)
在一对多的案例中:一个老师可以对应多个学生,此时的个体是学生(即:学生类中不会存在包含其他的类对象属性),老师和学生之间的关系时:”包含“,即:每一个老师都可能包含一个或多个学生对象。(集合代指多个对象)
注意:其实没有所谓的多对多,其实只有一对多或者多对一,多对多用的也是这两个理念。
多对一:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J7aYmfR4-1582305117232)(MyBatis学习笔记.assets/1569909163944.png)]
- 多个学生 对应 一个老师
- 对于学生这边而言与老师的关系时:[ 关联] ,多个学生关联一个老师 【多对一】
- 对于老师而言与学生的关系是:[集合] , 一个老师有很多学生 【一对多】
案例演示:
准备:数据库:
CREATE TABLE `teacher` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT INTO teacher(`id`, `name`) VALUES (1, '秦老师');
CREATE TABLE `student` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
`tid` INT(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fktid` (`tid`),
CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('1', '小明', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', '小红', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', '小张', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', '小李', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', '小王', '1');
0、创建Mybatis项目(或者创建Maven项目导入Mybatis模块)
项目目录如下结构所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-50rRZveY-1582305117232)(MyBatis学习笔记.assets/image-20200221204611268.png)]
1、编写pom.xml文件:添加依赖
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>Mybatis-Test</artifactId>
<groupId>edu.nwu</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mybatis-02</artifactId>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId> org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
</project>
2、编写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>
<!--xml 中元素的标签上下位置是有要求的-->
<!-- 将配置文件改为properties -->
<properties resource="db.properties"/>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
<!--<setting name="logImpl" value="STDOUT_LOGGING"/>-->
<!--<setting name="logImpl" value="LOG4J"/>-->
</settings>
<!--包的别名配置-->
<typeAliases>
<!-- 给包下所有类起别名 -->
<package name="edu.nwu.pojo"/>
<!-- 给一个类起别名 alias是自己起的别名-->
<!--<typeAlias type="edu.nwu.pojo.User" alias="User"/>-->
</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/mybatis?-->
<!--useSSL=true&useUnicode=true&characterEncoding=utf8"/>-->
<!--<property name="username" value="root"/>-->
<!--<property name="password" value="123456"/>-->
<!--</dataSource>-->
<!--</environment>-->
<!--</environments>-->
<!-- 一个environments 标签元素可以有多套配置 -->
<environments default="development">
<!-- 里面的每一个environment代表一个具体的环境 -->
<environment id="development">
<!--transactionManager 事务管理器 -->
<transactionManager type="JDBC"/>
<!-- dataSource 数据源配置 -->
<dataSource type="POOLED">
<!-- 连接数据库的配置i-->
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<package name="edu.nwu.dao"/>
</mappers>
</configuration>
其中数据库的相关信息都在db.properties下:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf8
username=root
password=123456
3、编写工具类:(注意这里的数据库事务自动提交与否,方法重载)
package edu.nwu.utils;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
// 工厂模式:
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}catch (IOException e){
e.printStackTrace();
}
}
// 获取sqlSession的连接:所有的增删改都需要我们手动提交事务
public static SqlSession getSession(){
return sqlSessionFactory.openSession();
}
// 如果你增加了true这个参数,它就会自动提交事务。(不需要session.commit()了)
public static SqlSession getSession(boolean flag){
return sqlSessionFactory.openSession(flag);
}
}
4、编写pojo下的实体类:要在Student中体现多对一
package edu.nwu.pojo;
import lombok.Data;
@Data
public class Student {
private int id;
private String name;
// 学生需要管理一个老师
private Teacher teacher;
}
package edu.nwu.pojo;
import lombok.Data;
import java.util.List;
@Data
public class Teacher {
private int id;
private String name;
}
5、编写接口类:StudentMapper
package edu.nwu.dao;
import edu.nwu.pojo.Student;
import java.util.List;
public interface StudentMapper {
List<Student> getStudents();
// 连接查询获得学生对象
Student getStudentById(int id);
// 子查询获得学生对象
Student getStudentById2(int id);
}
6、编写resources包下对应的配置文件: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 namespace="edu.nwu.dao.StudentMapper">
<select id="getStudents" resultType="Student">
select * from student;
</select>
<!--连接查询的写法:-->
<select id="getStudentById" resultMap="StudentTeacher">
select s.name sname,s.id sid,t.name tname,t.id tid
from student s,teacher t
where s.tid = t.id and s.id = #{id}
</select>
<resultMap id="StudentTeacher" type="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<!--多对一使用的是:association关联,相当于设置表中这个属性关联的是一个对象-->
<association property="teacher" javaType="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
</association>
</resultMap>
<!--子查询的写法:-->
<select id="getStudentById2" resultMap="StudentTeacher2">
select * from student where id = #{id}
</select>
<resultMap id="StudentTeacher2" type="Student">
<!--多对一使用的是:association关联,相当于设置表中这个属性关联的是一个对象-->
<association property="teacher" javaType="Teacher" column="tid" select="selectTeacher"/>
</resultMap>
<!--子查询语句:-->
<select id="selectTeacher" resultType="Teacher">
select * from teacher where id= #{tid};
</select>
</mapper>
7、编写测试代码进行测试:
联表查询:
@org.junit.Test
public void selectById(){
SqlSession session = MybatisUtils.getSession();
StudentMapper mapper = session.getMapper(StudentMapper.class);
Student student = mapper.getStudentById(1);
System.out.println(student);
session.close();
}
执行结果:
==> Preparing: select s.name sname,s.id sid,t.name tname,t.id tid from student s,teacher t where s.tid = t.id and s.id = ?
==> Parameters: 1(Integer)
<== Columns: sname, sid, tname, tid
<== Row: 小明, 1, 秦老师, 1
<== Total: 1
Student(id=1, name=小明, teacher=Teacher(id=1, name=秦老师))
嵌套查询:
@org.junit.Test
public void test3(){
SqlSession session = MybatisUtils.getSession();
StudentMapper mapper = session.getMapper(StudentMapper.class);
Student student = mapper.getStudentById2(2);
System.out.println(student);
session.close();
}
查询结果:
==> Preparing: select * from student where id = ?
==> Parameters: 2(Integer)
<== Columns: id, name, tid
<== Row: 2, 小红, 1
====> Preparing: select * from teacher where id= ?;
====> Parameters: 1(Integer)
<==== Columns: id, name
<==== Row: 1, 秦老师
<==== Total: 1
<== Total: 1
Student(id=2, name=小红, teacher=Teacher(id=1, name=秦老师))
区分联表查询和子查询:
- 联表查询:一条联表查询语句能够直接返回所得的数据,所以我们要做的工作是要把结果表中的每一条数据对应到类中去。此时Map的作用是将表中的结果映射到对象中去。
- 子查询:一条子查询语句要分两个阶段实行,第一阶段是查找学生信息,第二阶段才是通过学生表中对应的tid来查询teacher表中的对应记录。此时Map的作用是:需要再执行一条select语句来获取对应的结果才能和类对应匹配。
- 小结:其实联表查询更容易使用,但子查询更好理解一些。
一对多
概念:形如一个老师拥有多个学生!对于老师这个个体而言,就是一对多的关系!
0、创建Mybatis项目(或者创建Maven项目导入Mybatis模块)
项目目录如下结构所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yfKjB6wr-1582305117232)(MyBatis学习笔记.assets/image-20200221212230517.png)]
1、编写pom.xml配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>Mybatis-Test</artifactId>
<groupId>edu.nwu</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>Mybatis-01</artifactId>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId> org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
</project>
2、编写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>
<!--xml 中元素的标签上下位置是有要求的-->
<!-- 将配置文件改为properties -->
<properties resource="db.properties"/>
<settings>
<setting name="logImpl" value="NO_LOGGING"/>
<!--<setting name="logImpl" value="STDOUT_LOGGING"/>-->
<!--<setting name="logImpl" value="LOG4J"/>-->
</settings>
<!--包的别名配置-->
<typeAliases>
<!-- 给包下所有类起别名 -->
<package name="edu.nwu.pojo"/>
<!-- 给一个类起别名 alias是自己起的别名-->
<!--<typeAlias type="edu.nwu.pojo.User" alias="User"/>-->
</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/mybatis?-->
<!--useSSL=true&useUnicode=true&characterEncoding=utf8"/>-->
<!--<property name="username" value="root"/>-->
<!--<property name="password" value="123456"/>-->
<!--</dataSource>-->
<!--</environment>-->
<!--</environments>-->
<!-- 一个environments 标签元素可以有多套配置 -->
<environments default="development">
<!-- 里面的每一个environment代表一个具体的环境 -->
<environment id="development">
<!--transactionManager 事务管理器 -->
<transactionManager type="JDBC"/>
<!-- dataSource 数据源配置 -->
<dataSource type="POOLED">
<!-- 连接数据库的配置i-->
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<package name="edu.nwu.dao"/>
</mappers>
</configuration>
数据库配置文件:db.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf8
username=root
password=123456
3、编写实体类文件:要在Teacher中体现一对多
package edu.nwu.pojo;
import lombok.Data;
@Data
public class Student {
private int id;
private String name;
private int tid;
}
package edu.nwu.pojo;
import lombok.Data;
import java.util.List;
@Data
public class Teacher {
private int id;
private String name;
// 一个老师有多个学生
private List<Student> students;
}
4、编写接口文件:
package edu.nwu.dao;
import edu.nwu.pojo.Teacher;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface TeacherMapper {
// 获取老师
List<Teacher> getTeacher1();
// 获得指定老师下的所有学生及老师信息
Teacher getTeacher(@Param("tid") int id);
// 利用子查询来获得
Teacher getTeacher2(@Param("tid") int id);
}
5、编写接口对应的TeacherMappl.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="edu.nwu.dao.TeacherMapper">
<select id="getTeacher1" resultType="Teacher">
select * from teacher;
</select>
<!--利用连接查询的方式来获取结果-->
<select id="getTeacher" resultMap="TeacherStudent">
select s.id sid,s.name sname,t.name tname,t.id tid
from student s,teacher t
where s.tid = t.id and t.id = #{tid}
</select>
<resultMap id="TeacherStudent" type="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<!--复杂的属性,我们需要单独处理,
对象:association;
集合:collection;
javaType="" 指定属性的类型!
集合中的泛型信息,我们使用ofType获取
-->
<collection property="students" javaType="ArrayList" ofType="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
<!--利用子查询的方式来获得结果-->
<select id="getTeacher2" resultMap="TeacherStudent2">
select * from teacher where id = #{tid}
</select>
<resultMap id="TeacherStudent2" type="Teacher">
<result property="id" column="id"/>
<collection property="students" javaType="ArrayList" ofType="Student" select="getStudentByTeacherId" column="id"/>
</resultMap>
<select id="getStudentByTeacherId" resultType="Student">
select * from student where tid = #{tid}
</select>
</mapper>
6、编写测试文件进行单元测试:
@org.junit.Test
public void test2(){
SqlSession session = MybatisUtils.getSession();
TeacherMapper mapper = session.getMapper(TeacherMapper.class);
Teacher techaer = mapper.getTeacher(1);
System.out.println(techaer);
session.close();
}
执行结果:
Teacher(id=1, name=秦老师, students=[Student(id=1, name=小明, tid=1), Student(id=2, name=小红, tid=1), Student(id=3, name=小张, tid=1), Student(id=4, name=小李, tid=1), Student(id=5, name=小王, tid=1)])
@org.junit.Test
public void test3(){
SqlSession session = MybatisUtils.getSession();
TeacherMapper mapper = session.getMapper(TeacherMapper.class);
Teacher teacher2 = mapper.getTeacher2(1);
System.out.println(teacher2);
}
执行结果:
Teacher(id=1, name=秦老师, students=[Student(id=1, name=小明, tid=1), Student(id=2, name=小红, tid=1), Student(id=3, name=小张, tid=1), Student(id=4, name=小李, tid=1), Student(id=5, name=小王, tid=1)])
ResultMap小结:
1、所有我们无法直接返回结果的,都需要做ResultMap结果映射集
2、结果映射需要保证返回的对象的属性和数据库查询出来的字段一一对应
11. 在Mybatis中使用注解开发
在Mybatis中新建一个项目的惯性思维:(本质:我们想利用Java操作数据)
1、每一个数据库表都有对应的pojo类(实体类)
2、每一个实体类都有一个对应的Mapper接口
3、每一个Mapper接口都有一个对应的Mapper.xml文件。
注意:这些必须要重复做的事情,在未来的项目开发中,我们可以通过一些工具类来自动一键生成代码
面向接口编程的本质:就是为了解耦
1、增加系统的可扩展性
2、接口中的方法可以复用
3、利于分层开发
dao(mapper) --> daoIml ---> service(业务接口) -->serviceImpl(业务实现类) --> Controller(控制层)
一旦使用注解开发,就可以省去XML的配置!每一个注解都对应一个标签:
- 在接口方法上使用注解
- 必须还要绑定到我们的MyBatis-Config中去(推荐是用扫描包的方法,通用性强 )
注解开发时需注意:
- 如果只有简单的增删改查的话,其实完全用注解就足够了,只不过复杂一点的SQL语句(连接,嵌套查询等),使用注解开发就很麻烦了。
- 只使用注解的情况下,就可以删除掉*.xml文件了(与接口对应的)
- 同时也要修改Mybatis核心配置文件中的mapper选项,将resources改为class,并且指向mapper下的接口。(使用包扫描比较合理,什么时候都能用)
- *.xml文件可以和注解同时起作用。必须和接口绑定并且在xml和接口都需要绑定到mybatis核心配置文件。
- 注解开发在Mybatis中并不是一个重点,在Spring中才会大量使用注解
- 在Mybatis中使用注解开发违背了解耦的思想,本来修改SQL语句是不用修改代码文件的(保证代码的绝对安全性)。
示例:
0、创建普通Maven项目并添加一个Mybatis的依赖
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8FpU7lF9-1582305117233)(MyBatis学习笔记.assets/image-20200221221953301.png)]
1、添加依赖:
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>edu.nwu</groupId>
<artifactId>Mybatis-03</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
<dependency>
<groupId> org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
</project>
2、编写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>
<!--xml 中元素的标签上下位置是有要求的-->
<!-- 将配置文件改为properties -->
<properties resource="db.properties"/>
<settings>
<setting name="logImpl" value="NO_LOGGING"/>
<!--<setting name="logImpl" value="STDOUT_LOGGING"/>-->
<!--<setting name="logImpl" value="LOG4J"/>-->
</settings>
<!--包的别名配置-->
<typeAliases>
<!-- 给包下所有类起别名 -->
<package name="edu.nwu.pojo"/>
<!-- 给一个类起别名 alias是自己起的别名-->
<!--<typeAlias type="edu.nwu.pojo.User" alias="User"/>-->
</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/mybatis?-->
<!--useSSL=true&useUnicode=true&characterEncoding=utf8"/>-->
<!--<property name="username" value="root"/>-->
<!--<property name="password" value="123456"/>-->
<!--</dataSource>-->
<!--</environment>-->
<!--</environments>-->
<!-- 一个environments 标签元素可以有多套配置 -->
<environments default="development">
<!-- 里面的每一个environment代表一个具体的环境 -->
<environment id="development">
<!--transactionManager 事务管理器 -->
<transactionManager type="JDBC"/>
<!-- dataSource 数据源配置 -->
<dataSource type="POOLED">
<!-- 连接数据库的配置i-->
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<!--<mapper resource="edu/nwu/mapper/UserMapper.xml"/>-->
<!--<mapper resource="edu/nwu/mapper/UserMapperX.xml"/>-->
<package name="edu.nwu.mapper"/>
</mappers>
</configuration>
数据库相关配置文件:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf8
username=root
password=123456
3、编写接口类文件:(使用注解编写SQL语句,无序配置相应的*.xml文件了)
package edu.nwu.mapper;
import edu.nwu.pojo.User;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
public interface UserMapper {
@Select("select * from user where id = #{id}")
User getUser(int id);
@Update("update user set name=#{name},pwd=#{pwd} where id=#{id}")
int updateUser(User user);
@Insert("insert into user (`id`,`name`,`pwd`)values(#{id},#{name},#{pwd})")
int addUser(User user);
@Delete("delete from user where id = #{id}")
int delUser(int id);
}
4、测试结果:(编写测试文件)
package edu.nwu.mapper;
import edu.nwu.pojo.User;
import edu.nwu.utils.MybatisUtils;
import org.apache.ibatis.annotations.Update;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
public class UserMapperTest {
@Test
public void testGetUser(){
SqlSession session = MybatisUtils.getSession();
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.getUser(1);
System.out.println(user);
}
@Test
public void testUpdateUser(){
SqlSession session = MybatisUtils.getSession(true);
UserMapper mapper = session.getMapper(UserMapper.class);
int result = mapper.updateUser(new User(1, "小哆", "666666"));
System.out.println(result);
}
@Test
public void testAddUser(){
SqlSession session = MybatisUtils.getSession(true);
UserMapper mapper = session.getMapper(UserMapper.class);
int i = mapper.addUser(new User(8, "嘿嘿", "ssssss"));
System.out.println(i);
}
@Test
public void testDelUser(){
SqlSession session = MybatisUtils.getSession(true);
UserMapper mapper = session.getMapper(UserMapper.class);
int i = mapper.delUser(1);
System.out.println(i);
}
}
小结:
- 利用注解开发在Mybatis中比操作
.xml
要快捷的多 - 但是功能很受限,一旦遇到复杂的查询,就必须转回使用
.xml
进行配置。
13、动态SQL
参考:Mybatis动态SQL学习笔记,独立的一篇文章!