1.创建项目
groupid和artifactId被统称为“坐标”是为了保证项目唯一性而提出的,如果你要把你项目弄到maven本地仓库去,你想要找到你的项目就必须根据这两个id去查找。
groupId和artifactId是maven管理项目包时用作区分的字段,就像是地图上的坐标。
artifactId:artifactId一般是项目名或者模块名。
groupId:groupId分为几个字段,例如cn.com.fullstack,前面的com叫【域】,后面的是你自己起的域名。
groupId一般分为多个段,这里我只说两段,第一段为域,第二段为公司名称。域又分为org、com、cn等等许多,其中org为非营利组织,com为商业组织。举个apache公司的tomcat项目例子:这个项目的groupId是org.apache,它的域是org(因为tomcat是非营利项目),公司名称是apache,artigactId是tomcat。
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.dai</groupId>
<artifactId>springboot-web</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-web</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--thymeleaf-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-autoconfigure</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.7</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
<!--添加资源访问配置-->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
<include>**/*.yml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
</project>
2.配置文件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核心配置文件-->
<configuration>
<!-- -->
<environments default="development">
<environment id="development">
<!-- 事物管理 默认使用JDBC-->
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!--驱动-->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?userSSL=false&useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/dai/mapper/UserMapper.xml"/>
</mappers>
</configuration>
将UserMapper.xml配置到mybatis-config.xml文件中
<mappers>
<mapper resource="com/dai/mapper/UserMapper.xml"/>
</mappers>
2.1映射器mappers
方式一
<!-- 使用相对于类路径的资源引用 -->
<mappers>
<mapper resource="com/dai/mapper/UserMapper.xml"/>
</mappers>
方式二
<!--每个Mapper.XML都需要在Mybatis核心配置文件中注册-->
<mppers>
<mpper class="com.dai.mapper.UserMapper"/>
</mppers>
注意
接口和他的Mapper配置文件必须同名!!
接口和他的Mapper配置文件必须要在同一个包下!!
方式三
<!--每个Mapper.XML都需要在Mybatis核心配置文件中注册-->
<mppers>
<package name="com.dai.mapper"/>
</mppers>
接口和他的Mapper配置文件必须同名!!
接口和他的Mapper配置文件必须要在同一个包下!!
3.MybatisUtils工具类
从mybatis-config.xml文件中获取数据源,创建sqlSessionFactory中获取sqlSession实例。
package com.dai.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 {
//使用Mybatis第一步获取:sqlSessionFactory对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//既然有了SqlSessionFactory,顾名思义,我们就可以从中获取SqlSession的实例
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}
3.1、作用域(Scope)和生命周期
生命周期,和作用域,是至关重要的,因为错误的使用会导致非常严重的并发问题。
SqlSessionFactoryBuilder
一旦创建了SqlSessionFactory,就不需要他了
局部变量
SqlSessionFactory
说白了就是可以想象为:数据库连接池
SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例
因此 SqlSessionFactory 的最佳作用域是应用作用域
最简单的就是使用单例模式或者静态单例模式。
SqlSession
连接到连接池的一个请求
SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
用完之后要赶紧关闭,否则资源被占用
4.entity类
package com.dai.entity;
public class User {
Integer id;
String name;
String pwd;
public User() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", pwd='" + pwd + '\'' +
'}';
}
}
5.UserMapper接口
package com.dai.mapper;
import com.dai.entity.User;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface UserMapper {
/**
* 根据id查询用户信息
* @param id
* @return
*/
User getUserInfo(int id);
/**
* 新增用户
* @param user
* @return
*/
int save (User user);
/**
* 更新用户信息
* @param user
* @return
*/
int update (User user);
/**
* 根据id删除
* @param id
* @return
*/
int deleteById (int id);
/**
* 查询所有用户信息
* @return
*/
List<User> selectAll ();
/**
* 查询所有用户信息
* @return
*/
List<User> getUserList();
}
6.UserMapper.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="com.dai.mapper.UserMapper">
<-----接口方法------返回数据类型>
<select id="getUserList" resultType="com.dai.entity.User">
select * from mybatis.user
</select>
<select id="getUserById" parameterType="int" resultType="com.dai.entity.User" >
select * from mybatis.user where id = #{id};
</select>
<select id="getUserById" parameterType="int" resultType="com.dai.entity.User" >
select * from mybatis.user where id = #{id};
</select>
<update id="updateUSer" parameterType="com.dai.entity.User">
update mybatis.user set name=#{name},pwd=#{pwd} where id=#{id};
</update>
<delete id="delUser" parameterType="int">
delete from mybatis.user where id = #{id};
</delete>
7. MyTest测试类
package com.dai;
import com.dai.entity.User;
import com.dai.mapper.UserMapper;
import com.dai.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class MyTest {
@Test
public void test(){
//第一步: 获取SqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
//方式一:getMapper
UserMapper userDao = sqlSession.getMapper(UserMapper.class);
List<User> userList = userDao.getUserList();
for(User user : userList){
System.out.println(user);
}
//关闭SqlSession
sqlSession.close();
}
}
8.易错点
配置文件没有注册
绑定接口错误
方法名不对
返回类型不对 resultType
Maven导出资源问题标签不匹配的错误
resource绑定mapper,需要使用路径
程序配置文件必须符合规范!
NullPointerException,没有注册资源 例作用域问题
输出的xml文件中存在中文乱码问题
maven资源没有导出问题!
9.resultMap 结果集映射
<!--结果集映射-->
<resultMap id="UserMap" type="user">
<!--column数据库的字段,property实体类的属性-->
<result column="id" property="id"/>
<result column="name" property="name"/>
<result column="pwd" property="password"/>
</resultMap>
<select id="getUserById" parameterType="int" resultMap="UserMap" >
select * from mybatis.user where id = #{id};
</select>
resultMap元素是MyBatis中最重要最强大的元素
ResultMap的设计思想是,对于简单的语句根本不需要配置显示的结果映射,而对于复杂一点的语句只需要描述他们的关系就行了
ResultMap 最优秀的地方在于,虽然你已经对他相当了解了,但你根本就不需要显示的用到他们
如果世界总是这么简单就好了
10.日志工厂
SLEF4
LOG4J 【掌握】
LOG4J2
JDK_LOGGING
COMMONS_LOGGING
STDOUT_LOGGING【掌握】
NO_LOGGING
<!--日志文件-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
导包
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
日志格式配置log4j.properties
#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger = DEBUG,console ,file
#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold = DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern = [%c]-%m%n
#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File = ./log/kun.log
log4j.appender.file.MaxFileSize = 10mb
log4j.appender.file.Threshold = DEBUG
log4j.appender.file.layout = org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern = [%p][%d{yy-MM-dd}][%c]%m%n
#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
<!--日志文件-->
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
使用log4j日志
1.在要使用Log4j的类中,导入包import org.apache.log4j.Logger;
2.日志对象,参数为当前类的class
static Logger logger = Logger.getLogger(UserMapper.class);
3.日志级别
logger.info("info:进入了testLog4j");
logger.debug("debug:进入了testLog4j");
logger.error("error:进入了testLog4j");
11.多对一结果映射
多个学生,对应老师
对于这边而言,关联。。 多个学生,关联一个老师【多对一】
对于老师而言,集合。。 一个老师,有很多学生 【一对多】
11.1按照查询嵌套处理
<!--
思路:
1. 查询所有的学生信息
2. 根据查询出来的学生的tid寻找特定的老师 (子查询)
-->
<select id="getStudent" resultMap="StudentTeacher">
select * from student
</select>
<resultMap id="StudentTeacher" type="student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<!--复杂的属性,我们需要单独出来 对象:association 集合:collection-->
<collection property="teacher" column="tid" javaType="teacher" select="getTeacher"/>
</resultMap>
<select id="getTeacher" resultType="teacher">
select * from teacher where id = #{id}
</select>
11.2按照结果嵌套 处理
<!--按照结果进行查询-->
<select id="getStudent2" resultMap="StudentTeacher2">
select s.id sid , s.name sname, t.name tname
from student s,teacher t
where s.tid=t.id
</select>
<!--结果封装,将查询出来的列封装到对象属性中-->
<resultMap id="StudentTeacher2" type="student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javaType="teacher">
<result property="name" column="tname"></result>
</association>
</resultMap>
12.一对多处理
12.1按照查询嵌套处理
<!--(子查询)-->
<select id="getTeacher2" resultMap="TeacherStudent2">
select * from mybatis.teacher where id=#{tid};
</select>
<resultMap id="TeacherStudent2" type="Teacher">
<collection property="students" javaType="ArrayList" ofType="Student" select="getStudent" column="id"/>
</resultMap>
<select id="getStudent" resultType="Student">
select * from mybatis.student where tid=#{tid};
</select>
12.2按照结果嵌套查询
<!--按照结果嵌套处理-->
<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" ofType="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
总结
小结:
关联 - association 【多对一】
集合 - collection 【对多】
JavaType & ofType
JavaType 用来指定实体类中属性的类型
ofType 用来指定映射到List或者集合中的pojo类型,泛型中的约束类型
注意点:
尽量保证SQL的可读性,尽量保证通俗易懂
注意一对多、多对一中,属性名和字段问题!!
如果问题不好排除,可以使用日志~ 建议Log4j 【其实默认的也够用了】
13.动态SQL
13.1if
<!--parameterType 输入类型
resultType 返回结果集
-->
<select id="queryBlogIF" parameterType="map" resultType="blog">
select * from mybatis.blog where 1=1
<if test="title != null">
and title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</select>
13.2choose (when,otherwise)
<select id="queryBlogChoose" parameterType="map" resultType="blog">
select * from mybatis.blog
<where>
<choose>
<when test="title != null">
title = #{title}
</when>
<when test="author != null">
and author = #{author}
</when>
<otherwise>
and views=#{views}
</otherwise>
</choose>
</where>
</select>
13.3trim (where, set)
<!-- where标签 会去除多余的 “AND” 或 “OR”,或 "where" -->
<select id="queryBlogIF" parameterType="map" resultType="blog">
select * from mybatis.blog
<where>
<if test="title != null">
and title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</where>
</select>
所谓的动态SQL,本质还是SQL语句,只是我们可以在SQL层面,去执行一个逻辑代码
13.4sql片段
1.使用SQL标签抽取公共部分
<sql id="sql-if-title-author">
<if test="title != null">
title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</sql>
2.在需要使用的地方使用Include标签引用即可
<!--parameterType 输入类型
resultType 返回结果集
-->
<select id="queryBlogIF" parameterType="map" resultType="blog">
select * from mybatis.blog
<where>
<include refid="sql-if-title-author"/>
</where>
</select>
注意:
最好基于单表定义SQL片段!!
sql标签不要存在where标签 因为他是动态的
13.5Foreach
select * from user where 1=1 and
<foreach item="id" collection="ids" open="(" separator="or" close=")">
#{id}
</foreach>
(id=1 or id=2 or id=3)
<!--
集合 select * from user where 1=1 and (id=1 or id=2 or id=3)
我们现在传递一个万能的map,这map可以存在一个集合!
collection:集合 item:集合里的数据
-->
<select id="queryBlogForeach" parameterType="map" resultType="blog">
select * from mybatis.blog
<where>
<foreach item="id" collection="ids" open="and (" separator="or" close=")">
id=#{id}
</foreach>
</where>
</select>