Mybatis框架
Mybatis框架官网
mybatis官网:https://mybatis.org/mybatis-3/zh/index.html
一 、 jdbc回顾
图示:
1 jdbc的问题:
1、加载驱动问题:
每次执行都加载驱动
驱动名称,硬编码到java代码中,如果需要修改驱动。需要修改java文件
解决方案:将驱动名称放入到外部的配置文件
2、数据库的连接信息,硬编码到java代码中,解决方案:外部配置文件
3、设置参数的问题:
参数下标硬编码了。需要人为的去判断参数的位置。
4、遍历结果集:需要人工的判断字段名,以及个位置参数类型,不方便
是否可以:能够将结果集直接映射到一个pojo对象中
5、频繁的创建连接,关闭连接。导致资源浪费,影响性能,解决:连接池。
图示:
二 、 Mybatis介绍
什么是ORM
ORM,即Object Relational Mapping,它是对象关系模型的简称。它的作用是在关系型数据库和对象之间作一个映射。使程序能够通过操纵描述对象方式来操纵数据库
MyBatis
是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
介绍图示: 在mybatis的包里面可以看到,ibatis的字样
每一个框架都有一个核心配置文件,这个核心文件你必须会,不会这个框架就用不了
1 五大框架
SSH
spring
struts2(web == controller—[servlet])
hibernate (dao === jdbc—db)
SSM
spring
springmvc(web == controller—[servlet] service[m] )
mybatis(dao === jdbc—db)
2 mybatis的整体架构
图示:
导入依赖
// <!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
//<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
编写全局配置文件·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>
//<!--引入外部的jdbc.properties-->
<properties resource="jdbc.properties"/>
// <!--搭建环境配置-->
<environments default="development">
<environment id="development">
//<!--事务管理-->
<transactionManager type="JDBC"/>
//<!--数据源 : 连接数据库配置-->
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
//<!--映射配置文件所在地,可以有多个mapper,这个文件是你要进行操作sql语句所在配置文件-->
<mappers>
<mapper resource="com/hisoft/dao/UserMapper.xml"/>
</mappers>
</configuration>
jdbc.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql:///mybatis_db?characterEncoding=UTF-8
username=root
password=123456
读取所有的xml文件配置,使得target中也有xml文件
·
pom.xml
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
</build>
实体类注解生成getter serter方法
需要导包
:
idea下载lombok 插件:打开Settings→Plugins→下载小辣椒Lombok
//<!--简化pojo lombok 需要下载lombok 插件才能用-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
@NoArgsConstructor
//无参构造方法
@AllArgsConstructor
//全参构造方法
@ToString
//toString方法
@Data//生成setter getter方法
@NoArgsConstructor//无参构造方法
@AllArgsConstructor//全参构造方法
@ToString//toString方法
public class User {
private int id;
private String userName;
private String sex;
}
编写User对应的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" >
//<!--namespace:命名空间, 空间名称,一般是所操作的类所在地完全限定名,使用动态代理实现类必的话须得是该接口所在完全限定名-->
<mapper namespace="com.hisoft.dao.UserMapper">
<insert id="addUser">
insert into tb_user(id,user_name,sex) values (#{id},#{userName},#{sex})
</insert>
<update id="updateUser">
update tb_user set user_name=#{userName} , sex=#{sex} where id = #{id}
</update>
<delete id="deleteUserById">
delete from tb_user where id = #{id}
</delete>
<select id="findAllUser" resultType="User">
select id,user_name userName,sex from tb_user
</select>
//原先方式:(resultType:实体类所在地的完全限定名) <select id="queryUserById" resultType="com.hisoft.pojo.User"
<select id="queryUserById" resultType="User">/*在mybatis-config.xml配置文件中配置该别名后的方式*/
select * from tb_user where id = #{id}
</select>
</mapper>
从 XML 中构建 SqlSessionFactory
每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。
从 XML 文件中构建 SqlSessionFactory 的实例非常简单,建议使用类路径下的资源文件进行配置。 但也可以使用任意的输入流(InputStream)实例,比如用文件路径字符串或 file:// URL 构造的输入流。MyBatis 包含一个名叫 Resources 的工具类,它包含一些实用方法,使得从类路径或其它位置加载资源文件更加容易。
String resource = "mybatis-config.xml";//先读取的配置资源
//读取外部的xml配置文件
InputStream inputStream = Resources.getResourceAsStream(resource);
// 从XML 文件中构建 SqlSessionFactory 的实例
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream,"online");//指定配置环境environment
// SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
sqlSession = sqlSessionFactory.openSession();//获取到sqlSession对象
//sqlSission.selectList("com.hisoft.dao.UserMapper.findAllUser");
//通过写实现类指定接口中的方法,为UserMapperImpl所注入sqlSession,因为在实现类中需要用到sqlSession
//userMapper = new UserMapperImpl(sqlSession);
动态代理mapper实现类
使用动态代理的目标是可以不用书写实现类,只需要书写接口和mapper.xml即可完成crud的操作
如果不想写实现类(UserDaoImpl ) ,只写接口UserDao ---- 就可以使用动态代理
因为在dao(mapper)的实现类中对sqlsession的使用方式很类似。mybatis提供了接口的动态代理
6.1. 名称空间
mapper.xml 根标签的 namespace 属性
如果希望使用mybatis通过的动态代理的接口,就需要namespace 中的值,和需要对应的Mapper(dao)接口的全路径一直
<mapper namespace="com.hisoft.dao.UserMapper">
<select id="findCount" resultType="Integer">
select count(*) from tb_user
</select>
</mapper>
private SqlSession sqlSession;//提升为全局变量
private UserMapper userMapper;//UserMapper 接口
@Before//测试之前先执行的方法,可以在里边设置一些参数或实例
public void setUp() throws Exception {
String resource = "mybatis-config.xml";//先读取的配置资源
InputStream inputStream = Resources.getResourceAsStream(resource);
// 从XML 文件中构建 SqlSessionFactory 的实例
//SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream,"online");//指定配置环境environment
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
sqlSession = sqlSessionFactory.openSession();//获取到sqlSession对象
//使用动态代理模式实现实现类的功能,生成代理对象
userMapper = sqlSession.getMapper(UserMapper.class);//方式需要代理的UserMapper接口
}
使用动态代理总结
添加日志支持
导入依赖
:
//<!--日志管理-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
mybatis-config.xml
<settings>
//<!--mybatis日志配置,需要加log4j包-->
<setting name="logImpl" value="LOG4J"/>
</settings>
loog4j.properties
//# 全局日志配置
log4j.rootLogger=ERROR, stdout
//# MyBatis 日志配置,跟踪日志,写的是跟踪的类的完全限定名
log4j.logger.com.hisoft.dao.UserMapper=TRACE
//# 控制台输出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
测试方法
工具生成测试方法,找到要测试的接口,鼠标方法类那里右键
测试依赖
//<!--测试依赖-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
<scope>test</scope>
</dependency>
mapUnderscoreToCamelCase用法:
开启驼峰匹配:从经典数据库的命名规则user_name,到经典java命名规则的映射userName
java命名规则:驼峰书写, 大小写区分两个单词的界限。举例: userName;
数据库经典命名规则:两个单词之间,使用下划线分割。举例:user_name
开启驼峰匹配:相当于去掉数据库名字中的下划线,然后在与java中的属性名进行对应。
数据库中的user_name 和java属性中的 userName 是一样的
<settings>
//<!--开启驼峰匹配,开启之后可以自动匹配属性名跟表的列名不一致问题,可以不用再通过改别名了-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
typeAliases的使用2—使用扫描包
<typeAliases>
//<!--法一:起别名,给UserMapper.xml中的resultType结果类型简化为User-->
<typeAlias type="com.hisoft.pojo.User" alias="User"/>
//<!--法二: 扫描pojo包然后自动改别名为出去包名后的类名-->
<package name="com.hisoft.pojo"/>
</typeAliases>
总例 mybatis使用步骤总结
图示:
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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.hisot</groupId>
<artifactId>myss</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
//<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<!--简化pojo lombok 需要下载插件才能用-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
// <!--日志管理-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
// <!--测试依赖-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
//读取所有的xml文件
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
</build>
</project>
dao
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" >
//<!--namespace:命名空间, 空间名称,一般是所操作的类所在地完全限定名,使用动态代理实现类必的话须得是该接口所在完全限定名-->
<mapper namespace="com.hisoft.dao.UserMapper">
<insert id="addUser">
insert into tb_user(id,user_name,sex) values (#{id},#{userName},#{sex})
</insert>
<update id="updateUser">
update tb_user set user_name=#{userName} , sex=#{sex} where id = #{id}
</update>
<delete id="deleteUserById">
delete from tb_user where id = #{id}
</delete>
<select id="findAllUser" resultType="User">
select id,user_name userName,sex from tb_user
</select>
//<!-- 原先方式:(resultType:实体类所在地的完全限定名) <select id="queryUserById" resultType="com.hisoft.pojo.User">-->
<select id="queryUserById" resultType="User">/*在mybatis-config.xml配置文件中配置该别名后的方式*/
select * from tb_user where id = #{id}
</select>
</mapper>
UserMapper
public interface UserMapper {
/**
* 根据id查询用户信息
* @param id
* @return
*/
User queryUserById(int id);
/**
* 查询所有用户信息
* @return
*/
List<User> findAllUser();
/**
* 根据id删除用户信息
* @param id
*/
void deleteUserById(int id);
/**
* 添加用户信息
* @param user
*/
void addUser(User user);
/**
* 修改用户信息
* @param user
*/
void updateUser(User user);
}
UserMapperImpl
public class UserMapperImpl implements UserMapper {
private SqlSession sqlSession;
public UserMapperImpl(SqlSession sqlSession) {
this.sqlSession = sqlSession;
}
@Override
public List<User> findAllUser() {
return sqlSession.selectList("com.hisoft.dao.UserMapper.findAllUser");
}
@Override
public void addUser(User user) {
sqlSession.insert("com.hisoft.dao.UserMapper.addUser", user);
sqlSession.commit();//事务提交
}
}
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>
//<!--jdbc所在配置文件-->
<properties resource="db.properties"/>
<settings>
//<!--mybatis日志配置,需要加log4j包-->
<setting name="logImpl" value="LOG4J"/>
//<!--开启驼峰匹配,开启之后可以自动匹配属性名跟表的列名不一致问题,可以不用再通过改别名了-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<typeAliases>
//<!--法一:起别名,给UserMapper.xml中的resultType结果类型简化为User-->
<typeAlias type="com.hisoft.pojo.User" alias="User"/>
//<!--法二: 扫描pojo包然后自动改别名为出去包名后的类名-->
<package name="com.hisoft.pojo"/>
</typeAliases>
//<!--搭建环境配置-->
<environments default="development">
<environment id="development">
//<!--事务管理-->
<transactionManager type="JDBC"/>
//<!--数据源 : 连接数据库配置-->
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
<environment id="online">
//<!--事务管理-->
<transactionManager type="JDBC"/>
//<!--数据源 : 连接数据库配置-->
<dataSource type="POOLED">
<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-->
<mapper resource="com/hisoft/dao/UserMapper.xml"/>
</mappers>
</configuration>
test
package com.hisoft.dao;
import com.hisoft.pojo.User;
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 org.apache.log4j.lf5.util.Resource;
import org.junit.Before;
import org.junit.Test;
import java.io.InputStream;
import java.util.List;
public class UserMapperTest {
private SqlSession sqlSession;//提升为全局变量
private UserMapper userMapper;
@Before//测试之前先执行的方法,可以在里边设置一些参数或实例
public void setUp() throws Exception {
String resource = "mybatis-config.xml";//先读取的配置资源
InputStream inputStream = Resources.getResourceAsStream(resource);
// 从XML 文件中构建 SqlSessionFactory 的实例
//SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream,"online");//指定配置环境environment
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
sqlSession = sqlSessionFactory.openSession();//获取到sqlSession对象
//通过写实现类指定接口中的方法,为UserMapperImpl所注入sqlSession,因为在实现类中需要用到sqlSession
//userMapper = new UserMapperImpl(sqlSession);
//使用动态代理模式实现实现类的功能,生成代理对象
userMapper = sqlSession.getMapper(UserMapper.class);//方式需要代理的UserMapper接口
}
@Test
public void findAllUser() {
List<User> userList = userMapper.findAllUser();
userList.forEach(System.out::println);
}
@Test
public void addUser() {
User user = new User(11, "老大", "男");
userMapper.addUser(user);
}
}
3 整理mybatis-config中的内容
//2、xsettings:开启驼峰匹配。
//从数据库的经典命名规则到java经典命名规则的映射; 把数据库中的下划线去顶在和java中的内容进行映射。
<settings>
<setting name="mapUnderscoreToCamelCase" value="true" />
</settings>
//3、typealiases:类型别名。 为一些java对象,去起一个简写的名字,减少mapper.xml中的 代码书写量。
<typeAliases>
<package name="comisoft.mybatis.pojo"/>
</typeAliases>
//4、环境:数据库的连接信息
//5、mappers:关联外部的mapper.xml文件的
//把外部的mapper.xml加载到mybatis中
//扫描包的方式:
<mappers>
<!--
//扫描指定包下面的所有的接口
//要求:
//1、要求mapper.xml文件的名字和mapper接口的名字,一致
// 2、要求mapper.xml文件 和 mapper接口类在一个目录下
-->
// <!--方法3,扫描包的形式(常用)-->
1 <package name="com.hisoft.dao"/>
//UserMapper.xml所在路径
2 <mapper resource="com/hisoft/dao/UserMapper.xml"/>
//通过接口类,类名要和文件名一致且在同一个目录下
3 <mapper class="com.hisoft.dao.UserMapper"/>
//放在resource目录下然后建个mapper子包
4 <mapper resource="mapper/UserMapper.xml"/>
</mappers>
二 、 Mapper.xml
插件绿色箭头设置
1 CURD操作
select
select – 书写查询sql语句
id属性:当前名称空间下的statement的唯一标识。必须。要求id和mapper接口中的方法的名字一致。
Select 标签中 resultType:将结果集映射为java的对象类型必须要有(和 resultMap 二选一)
parameterType:传入参数类型。可以省略,会自判断传入的是什么类型
要求:查询当前有多少人: mapper映射文件
接口方法
/**
* 查询表的总行数
* @return
*/
Integer findCount();
测试
@Test
public void findCount(){
Integer count = userMapper.findCount();
System.out.println("总数:" + count);
}
传多个参数查值
`接口方法:
/**
* 根据用户名字和性别查找用户
* @param userName
* @param sex
* @return
*/
法1: User findUserByNameAndSex(
@Param("userName") String userName,
@Param("sex") String sex
);
法2: 或者也可以这样
User findUserByNameAndSex(String userName,String sex);
mapper.xml映射文件:
<select id="findUserByNameAndSex" resultType="User">
//如果是通过${}的话得加单引号'' , 例:user_name= '${userName}'
select * from tb_user where user_name=#{userName} and sex=#{sex}
</select>
***********法2: 不推荐使用************************
<select id="findUserByNameAndSex" resultType="User">
select * from tb_user where user_name=#{param1} and sex=#{param2}//param1:第一个参数,param2:第二个参数 索引从1开始
</select>
或: //arg0:第一个参数,arg1:第二个参数,索引从0开始 低版本mybatis索引是:#{0},#{1}
<select id="findUserByNameAndSex" resultType="User">
select * from tb_user where user_name=#{arg0} and sex=#{arg1}
</select>
测试:
@Test
public void findUserByNameAndSex(){
User user = userMapper.findUserByNameAndSex("乔峰", "男");
System.out.println("用户:" + user);
}
模糊查询
·接口方法
/**
* 模糊查询
* @param userName
* @return
*/
List<User> findUserByLike(@Param("userName") String userName);
·mapper.xml映射文件
<select id="findUserByLike" resultMap="userResultMap">
1 select * from tb_user where user_name like '${userName}'
或:
2 select * from tb_user where user_name like #{userName}
</select>
测试:
@Test
public void findUserByLike(){
List<User> userByLikes = userMapper.findUserByLike("%龙%");
userByLikes.forEach(System.out::println);
}
insert
获取自增的主键id值和返回受影响的条数
insert 的几个属性说明:
id属性:当前名称空间下的statement的唯一标识(必须属性);//statement:声明,语句
parameterType:传入的参数类型,可以省略。
标签内部:具体的sql语句。insert语句
使用#{} 去替换一个变量。
怎么知道我们添加时是否添加成功怎么办?
UserMapper.java 接口中把返回类型直接写成Integer返回类型,其他的不用动
可以拿到数据库的自增长的id值
useGeneratedKeys="true"
:是否使用主键会写功能。默认是false
keyProperty
:java对象主键属性名(在实体类中的id属性)
keyColumn
:数据库主键对应的字段的名字(主键的列名)
mapper映射
<mapper namespace="com.hisoft.dao.RoleMapper">
<insert id="addRole" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
insert into t_role(role_name) values (#{roleName} )
</insert>
</mapper>
接口方法;
/**
* 添加角色
* @param role
* @return
*/
Integer addRole(Role role);
测试: (如果是已经纳入事务管理的话增删改需要提交事务)
@Test
public void addRole() {
Role role = new Role(1, "张三");
Integer count = roleMapper.addRole(role);
sqlSession.commit();//提交事务
System.out.println("影响条数:" +count);
System.out.println("自增id值:" + role.getId());
}
update
update 的几个属性说明:
id属性:当前名称空间下的statement的唯一标识(必须属性);
parameterType:传入的参数类型,可以省略。
标签内部:具体的sql语句。
使用#{} 去替换一个变量。
接口方法:
/**
* 修改角色
* @param role
* @return
*/
Integer updateRole(Role role);
mapper映射文件
<mapper namespace="com.hisoft.dao.RoleMapper">
<update id="updateRole" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
update t_role set role_name=#{roleName} where id=#{id}
</update>
</mapper>
测试:
@Test
public void updateRole() {
Role role = new Role(8, "李四");
Integer count = roleMapper.updateRole(role);
sqlSession.commit();//提交事务
System.out.println("影响条数:" +count);
}
delete
delete 的几个属性说明:
id属性:当前名称空间下的statement的唯一标识(必须属性);
parameterType:传入的参数类型,可以省略。
标签内部:具体的sql语句。
使用#{} 去替换一个变量。
接口方法:
/**
* 删除角色
* @param id
* @return
*/
Integer deleteRole(int id);
RoleMapper.xml
映射文件
<mapper namespace="com.hisoft.dao.RoleMapper">
<delete id="deleteRole" >
delete from t_role where id = #{id}
</delete>
</mapper>
测试:
@Test
public void deleteRole() {
Integer count = roleMapper.deleteRole(8);
sqlSession.commit();//提交事务
System.out.println("影响条数:" +count);
}
3 ${}的用法----传入参数的,接受参数
#{}
?只能出现where中 ,当作一个变量 ,如要sql语句中要在实体对象中取出数据 ,那么where 后的#{}不能随便写
${}
数据:是进行字符串拼接。
如果使用${}
去取出参数信息,则需要在方法的参数列表上加上一个注释@param 表示参数的名字
#{}
只是表示占位,与参数的名字无关。会自动转换数据的类型,还能防止sql注入
sql语句动态生成的时候,使用${};
sql语句中某个参数进行占位的时候#{}
定义传入参数的类型:
如果 没 有 指 定 参 数 名 , 使 用 {} 没有指定参数名 ,使用 没有指定参数名,使用{value} 表示传递过来的参数。
如果接口中书写的@Param(“TableName”) 就输入 ${TableName}
//接口方法
List<Role> findAllRoleByTable( String tableName);
//RoleMapper.xml
<select id="findAllRoleByTable" resultType="Role">
select * from ${value}//等同于: select * from t_role
</select
preparamType传参数例子:
接口方法:
/**
* 根据表明查找所有Role
* @param table//到时候mapper映射文件那边就会自动通过${tableName}获取到传进去的表明然后拼接到sql语句上进行查询
* @return//这是和 #{}不一样的地方,#{}是占位,${}是拼接
*/@Param("tableName"):也可以省略不加,通过${}拿值是拿的就是@Param()里边的值,这里是给参数table改为tableName了
//一个参数
List<Role> findAllRoleByTable(@Param("tableName") String table);
//多个参数
List<Role> findAllRoleByTable(
@Param("tableName") String table,
@Param("columnName") String columnName
);
mapper映射文件
//传递一个参数
<select id="findAllRoleByTable" resultType="Role">
select * from ${tableName}//等同于: select * from t_role
</select>
//传递多个参数
<select id="findAllRoleByTable" resultType="Role">
select ${roleName }from ${tableName}//等同于: select role_name from t_role
</select>
preparamType传Map集合例子:
如果传入的是map集合,mapper.xml中使用
$
{key},$
{value}或(#
{key},#
{value})获取传的参数值
接口方法:
/**
* 传map集合查所有角色
* @param map
* @return//到时候根据map集合键获取到参数的值
*/
List<Role> findAllRoleByMap(Map map);
RoleMapper.xml映射文件
//columnName:map集合的键
<select id="findAllRoleByMap" resultType="Role">
select ${columnName} from ${tableName}//等同于select role_name from t_role
</select>
测试:
@Test
public void findAllRoleByMap() {
Map map = new HashMap<>();
map.put("columnName","role_name");
map.put("tableName","t_role");
//传进去map集合
List<Role> roleList = roleMapper.findAllRoleByMap(map);
roleList.forEach(System.out::println);
}
4 面试题:#{}与${}的区别
1、
$
字符串拼接,# 参数占位符相当于jdbc中的?
2、$
不能够防止sql注入,#可以防止sql注入的
3、$
可以替换sql语句任何一个内容,#只能替换参数
4、$
如果操作字符串,需要在sql中使用单引号。 #不需要(不需要判断数据类型,会自动转换)($
要考虑参类型 ,#不用考虑参数类型)
简单来说#{} 解析的是占位符?可以防止SQL注入, 比如打印出来的语句 select * from table where id= ? 然而$
{} 作为字符串拼接来用,则是不能防止SQL注入打印出来的语句 select * from table where id=2 实实在在的参数 sql注入:通过字符串拼接达到串改sql语句的目地)
${} statement
对象 //statement: 声明语句
#{} Preparedstatement
对象 //prepared: 准备,拟定
$
可以代替所有#
如果传入的数据,不是sql中的字段的时候,就不能够使用#.
通常使用#。
选择获取参数的时候,首要选择的# 的方式(1、可以防止sql注入,2、可以不用考虑数据类型,简化书写,3、sql是参数的话的sql,预编译的sql,速度会块一些)
当#用不了的时候,去选择$
例如 ,sql需要改变是表名的情况,就可使用·$
的方式。
总结:能用# 就不选择$
三 、 resultMap
图示:
1 mapper.xml映射文件
<mapper>
//<!--resultMap="" :手动映射,解决表明和属性名不一样的问题 resultType:开启驼峰命名后自动映射-->
//type:封装返回的对象类型 id="userResultMap":resultMap标识
<resultMap id="userResultMap" type="User" autoMapping="true">
<id column="id" property="id"/>//表主键id,实体类属性id
<result column="user_name" property="userName"/>//column:表的列名,property:User实体类的属性
//如果autoMapping="true",则表列名和属性名相同的话可以省略不写 <result column="sex" property="sex"/>,resultMap会自动映射,如果为false得写,默认是true
<result column="sex" property="sex"/>
</resultMap>
<select id="findAllUser" resultMap="userResultMap">
select * from tb_user
</select>
</mapper>
四 、sql片段
作用: 把重复的sql语句抽出来来放到sql标签中,然后通来引入
2 sql片段用法1:
直接在内部写sql片段
UserMapper.xml
<mapper>
<sql id="sqlSelectId">//sql标签:写sql片段
select * from tb_user
</sql>
//查询所有用户
<select id="findAllUser" resultMap="userResultMap">
<include refid="sqlSelectId"/>//通过sql标签的id值进行引入refid=sql标签的id值
</select>
//通过姓名性别查找用户
<select id="findUserByNameAndSex" resultType="User">
<include refid="sqlSelectId"/> where user_name=#{userName} and sex=#{sex}
</select>
</mapper>
2 sql片段用法2:
将所有的公用的SQL片段集中定义到一个Mapper.xml文件中,其他Mapper.xml文件如需引入mybatis-config.xml,通过命名空间.id即可。
\ \ \ 在外部新写一个sqlMapper.xml配置文件,然后通过映射文件的里的空间名称namespace点sql标签的id属性值(sql.outSqlSelectId
)进行引入
·UserMapper.xml配置文件
<mapper>
//查询所有用户
<select id="findAllUser" resultMap="userResultMap">
<include refid="sql.outSqlSelectId"/> //通过sql标签的id值进行引入refid=sql标签的id值
</select>
//通过姓名性别查找用户
<select id="findUserByNameAndSex" resultType="User">
<include refid="sql.outSqlSelectId"/> where user_name=#{userName} and sex=#{sex}
</select>
</mapper>
sqlMapper.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="sql">//namespace:空间名称
<sql id="sqlSelectId">//sql标签:写sql片段
select * from tb_user
</sql>
</mapper>
mybatis-config.xml
中的映射配置
//映射配置文件所在地,可以有多个mapper
<mappers>
//<!--因为sqlMapper.xml没有名称和它一样的接口,所以package扫描包的形式扫描不到,所以无法加入到mybatis-config.xml中-->
<mapper resource="com/hisoft/dao/sqlMapper.xml"/>
//<!--方法3,扫描包的形式(常用)--><!--前提:需要接口名称和xml配置文件名称一致-->
<package name="com.hisoft.dao"/>
</mappers>
总结整理:
思维导图:
五 、动态sql
1 if
进行判断:
需求1: 查询用户,如果输入了姓名,进行模糊查找,如果不输入就按男性获女性用户来查询。
1
:使用${}
的方式进行取出数据,要求在sql语句中 ‘%${}%’
2:
使用#{} 去取出数据,要求在传递参数的时候,就把% 进行拼接到参数上。%张%
3
: 使用mysql中的字符串拼接函数concat(), 例:concat(’%’ , #{参数} , ‘%’)
接口方法:
/**
* 查询用户,如果输入了姓名,进行模糊查找,如果不输入就按男性或女性用户来查询
* @param sex
* @param userName
* @return
*/
List<User> findUserBySexAndUserName(@Param("sex") String sex,@Param("userName") String userName);
mapper.xml映射
<resultMap id="userResultMap" type="com.hisoft.pojo.User" autoMapping="true">
<id column="id" property="id"/>
<result column="user_name" property="userName"/>
<result column="sex" property="sex"/>
</resultMap>
<select id="findUserBySexAndUserName" resultMap="userResultMap">
select * from tb_user where 1=1//1=1:是为了使sex,userName都为空时使where能够符合sql的语法规则恒成立
<if test="sex != null and sex != '' ">
and sex = #{sex}
</if>
<if test="userName != null and userName != '' ">
and user_name like concat('%' ,#{userName},'%')
</if>
</select>
测试:
@Test
public void findUserBySexAndUserName(){
List<User> userByLikes = userMapper.findUserBySexAndUserName("男","郭");
userByLikes.forEach(System.out::println);
}
2 choose,when,otherwise
choose,when,otherwise 相当于java中的 if, else if的逻辑
题目需求:
查询男性用户,如果输入了姓名则按照姓名模糊查找,否则如果输入了年龄则按照年龄查找。
mapper.xml映射文件
<select id="findUserBySexOrUserName" resultType="User">
select * from tb_user where 1=1
<choose>
<when test="sex != null and sex != '' ">
and sex=#{sex}
</when>
<when test="userName != null and sex != ''">
and user_name like concat('%' , #{userName} ,'%')
</when>
<otherwise></otherwise>//如果前边的条件都不满足最终会执行这个,相当于switch(){}中的defult语句
</choose>
</select>
3 where
作用:
完成WHERE和SET关键字,并且处理SQL语句的中语法错误。
Select * from t_user where …
Update from t_user set name = …
练习:
查询所有用户,如果输入了性别,按照性别查找,如果输入了姓名按照姓名进行模糊查询,where会自动把多余的and 去掉
where+if
mapper.xml映射文件
<select id="findUserBySexAndUserName" resultMap="userResultMap">
select * from tb_user
<where>
<if test="sex != null and sex != '' ">
and sex = #{sex}
</if>
<if test="userName != null and userName != '' ">
and user_name like concat('%' ,#{userName},'%')
</if>
</where>
</select>
4 set
作用:
Set标签 相当于 sql中 set 关键字
,<set>
会自动把多余的,
号去掉
需求:
果名字信息不是null,则修改名字, 如果sex信息不是null,同时也修改sex
接口方法:
/**
* 如果名字信息不是null,则修改名字, 如果sex信息不是null,同时也修改sex
* @param userName
* @param sex
* @param id
* @return
*/
void updateUserById(
@Param("userName") String userName,
@Param("sex") String sex,
@Param("id") Integer id
);
mapepr.xml映射文件·
<update id="updateUserById" >
update tb_user
<set>
<if test="userName != null and userName != ''">
user_name = #{userName},
</if>
<if test="sex != null and sex != ''" >
sex = #{sex},//,如果不需要的话<set>标签会自动帮我们去掉,号加上再说
</if>
</set>
where id = #{id}
</update>
测试:
@Test
public void updateUserById(){
userMapper.updateUserById("郭哥","男",12);
sqlSession.commit();
}
5 forEach
练习:
按照多个id查询用户信息
Select * from t_user where id in(1,2,3)
Collection: 要遍历的集合, item:接受遍历集合的值in( 1,2,3)
collection默认值:数组的话是array, 集合的话是:list ,arg0 ,collection
接口方法:
/**
* 传进一个数组,按照多个id用户,id存在数组中
* @param ids
* @return
*/
法1: List<User> findUserByArray(@Param("ids") int[] ids);
//按照多个id查询用户信息,id存在集合中
法2 :List<User> findUserByList(@Param("idList") List idList);
mapper.xml映射文件
做法1 ://传数组
<select id="findUserByArray" resultType="User">
select * from tb_user where id in
//collection:要遍历的集合,item:一个对应的id(和#{id}里的id一致)
//默认值写法:<foreach collection="array" item="id" open="(" close=")"
<foreach collection="ids" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</select>
*********做法二: 传集合******************************
<select id="findUserByList" resultType="User">
select * from tb_user where id in
//传参@Param不写时collection的默认取值方式: <foreach collection="list"(或arg0,collection) item="id" open="(" close=")" separator=",">
<foreach collection="idList" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</select>
测试:
@Test//测试法一
public void findUserByArray(){
int[] ids = new int[]{5,6,7};
List<User> userByArray = userMapper.findUserByArray(ids);
userByArray.forEach(System.out::println);
}
****************测试法二:*************************
@Test
public void findUserByList(){
//Arrays:java.util提供的一个工具类,调用asList方法可以把一组数快速存进一个集合
List<Integer> idList= Arrays.asList(5,6,7);
List<User> userByArray = userMapper.findUserByList(idList);
userByArray.forEach(System.out::println);
}
6 Trim
Trim介绍:
trim元素的主要功能是可以在自己包含的内容前加上某些前缀,也可以在其后加上某写后缀,与之对应的属性是prefix和suffix;
可以把包含内容的首部某些内容覆盖,即忽略,也可以把尾部的某些内容覆盖,对应的属性是prefixOverrides和suffixOver
trim标签
:可以代替上边例子中使用的where标签和set标签实现同样的功能
trim案例1:
<select id="findUserBySexAndUserName" resultMap="userResultMap">
select * from tb_user
//prefix:加上前缀where,prefixOverrides:去掉多余的and或or
<trim prefix="where" prefixOverrides="and | or">
//执行顺序:加上prefix然后if判断,然后如果and或or多余的话执行prefixOverrides去掉
<if test="sex != null and sex != '' ">
and sex = #{sex}
</if>
<if test="userName != null and userName != '' ">
and user_name like concat('%' ,#{userName},'%')
</if>
</trim>
</select>
trim案例2:
<update id="updateUserById" >
update tb_user
//加上前缀set,suffixOverrides:去掉后缀, suffix:加上后缀where id = #{id}
<trim prefix="set" suffixOverrides="," suffix="where id = #{id}" >
<if test="userName != null and userName != ''">
user_name = #{userName},
</if>
<if test="sex != null and sex != ''" >
sex = #{sex},
</if>
</trim>
</update>
六 、 缓存
缓存的查找顺序:
先从二级缓存找,找不到再从一级缓存找
1 一级缓存
在mybatis中,一级缓存默认是开启的,并且一直无法关闭(我们没法去管理一级缓存)
一级缓存满足条件:
1
、作用域: 同一个session中
2
、相同的SQL和参数
测试:
1 没清缓存
@Test
public void findUserByList(){
//Arrays:java.util提供的一个工具类,调用asList方法可以把一组数快速存进一个集合
List<User> userByArray = userMapper.findUserByList(Arrays.asList(5,6,7));
System.out.println("****第一次查询*****");
userByArray.forEach(System.out::println);
List<User> userByArray1 = userMapper.findUserByList(Arrays.asList(5,6,7));
System.out.println("****第二次查询*****");
userByArray1.forEach(System.out::println);
}
运行结果:
缓存区命中,日志只追踪到发送一次sql语句,第二次是直接从缓存中拿的
测试: 2 清缓存
@Test
public void findUserByList(){
List<User> userByArray = userMapper.findUserByList(Arrays.asList(5,6,7));
System.out.println("****第一次查询*****");
userByArray.forEach(System.out::println);
sqlSession.clearCache();//清除缓存
List<User> userByArray1 = userMapper.findUserByList(Arrays.asList(5,6,7));
System.out.println("****第二次查询*****");
userByArray1.forEach(System.out::println);
}
运行结果:
sqlSession.clearCache()清除缓存了,缓存区没命中,所以日志追踪到sql发送两次
update,delete,insert自动清理缓存
执行update,delete,insert 语句的时候 都会自动清空缓存 然后刷新
测试:
@Test
public void findUserByList(){
List<User> userByArray = userMapper.findUserByList(Arrays.asList(5,6,7));
System.out.println("****第一次查询*****");
userByArray.forEach(System.out::println);
//执行增,删,改会自动清理缓存
userMapper.addUser(new User(14,"缓存" ,"男"));
List<User> userByArray1 = userMapper.findUserByList(Arrays.asList(5,6,7));
System.out.println("****第二次查询*****");
userByArray1.forEach(System.out::println);
}
运行结果:
2 二级缓存
概念理解:
mybatis 的二级缓存的作用域是一个mapper的namespace ,同一个namespace中查询sql可以从缓存中命中。
二级缓存是跨session
开启二级缓存:
在mapper.xml映射文件中开启,则二级缓存只对nanspace控件名称所在的接口中的操作有效
开启二级缓存:
<mapper namespace="com.hisoft.dao.UserMapper">
//<!--开启二级缓存-->
<cache/>
//sql查询语句
<select id="queryUserById" resultMap="userResultMap">
<include refid="sql.outSqlSelectId"/>
where id = #{id}
</select>
</mapper>
测试:
public class UserMapperTest {
private SqlSession sqlSession;//提升为全局变量
private UserMapper userMapper;
private SqlSessionFactory sqlSessionFactory;
@Before//测试之前先执行的方法,可以在里边设置一些参数或实例
public void setUp() throws Exception {
String resource = "mybatis-config.xml";//先读取的配置资源
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactoryBuilder().build(inputStream);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
sqlSession = sqlSessionFactory.openSession();//第一次获取到sqlSession
//使用动态代理模式实现实现类的功能,生成代理对象
userMapper = sqlSession.getMapper(UserMapper.class);//方式需要代理的UserMapper接口
}
@Test//二级缓存测试
public void queryUserById() {
User user = userMapper.queryUserById(6);
System.out.println("第一次查询");
System.out.println(user);//第一次查询
sqlSession.close();//清除sqlSession
//重新获取sqlSession
SqlSession newSqlSession = sqlSessionFactory.openSession();
UserMapper newUserMapper = newSqlSession.getMapper(UserMapper.class);
System.out.println("第二次查询");
System.out.println(newUserMapper.queryUserById(6));
}
}
运行结果:
日志只追踪一次,作用域在nanspace空间名称的范围类都有效,作用域比以及缓存的大,一级缓存是只在同一个session中有效,二级缓存不在同一个session中也可以有效
二级缓存关闭总开关
在全局的mybatis-config.xml 中去关闭二级缓存
扩展知识:
七 、高级查询
1 一对一查询
例: 查询订单,并且查询出下单人的信息
核心思想: 面向对象的思想,在Order对象中添加User对象
接口方法:
/**
* 根据订单号查找用户信息
* @param orderNumber
* @return
*/
Order findOrderByOrderNumber(String orderNumber);
mapper.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.hisoft.dao.UserOrderMapper">
<resultMap id="orderMap" type="Order" autoMapping="true">
<id column="id" property="id"/>
//association标签用来在类中的私有属性为对象类型时将查询的值映射到该私有属性对象中 association:联想
<association property="user" javaType="User" autoMapping="true">
//<!--column用user_id是因为用id的话会和上边的id重,映射的时候不知道该是哪个,user_id是order里的外键同时也是user表里的id,值是一样的-->
<id column="user_id" property="id"/>
<result column="user_name" property="userName"/>
</association>
</resultMap>
//左连接查询,显示左表中的全部内容,在这里使用resultType是不能完成自动映射的,所以得用resultMap手动映射
<select id="findOrderByOrderNumber" resultMap="orderMap">
select * from tb_user
left join tb_order on tb_user.id = tb_order.user_id
where order_number = #{orderNumber}
</select>
</mapper>
测试:
@Test
public void findOrderByOrderNumber() {
Order userOrder = userOrderMapper.findOrderByOrderNumber("20140921001");
System.out.println(userOrder);
}
2 一对多查询
例:
一对多查询:查询订单,查询出下单人信息并且查询出订单详情。
一个定单可以有多个定单详情
接口方法:
/**
* 一对多查询:查询订单,查询出下单人信息并且查询出订单详情。
* 一个定单可以有多个定单详情
* @param orderNumber
* @return
*/
Order findOrderAndOrderDetailByOrderNumber(String orderNumber);
mapper.xml映射文件:
<mapper>
<resultMap id="OrderMapDetail" type="Order" autoMapping="true">
<id column="id" property="id"/>
//类中属性为对象时的映射
<association property="user" javaType="User" autoMapping="true">
<id column="user_id" property="id"/>
<result column="user_name" property="userName"/>
</association>
//collection:对类中属性为集合时的映射标签
//property:集合的变量名,javaType:集合的类型,ofType:集合的泛型
<collection property="orderDetailList" javaType="list" ofType="OrderDetail" autoMapping="true">
//<!--detail_id查询过取别名后的id,查询结果对应的列名是啥这就是啥-->
<id column="detail_id" property="id"/>
<result column="item_id" property="itemId"/>
</collection>
</resultMap>
<select id="findOrderAndOrderDetailByOrderNumber" resultMap="OrderMapDetail">
SELECT * , d.id AS detail_id FROM tb_order AS o
LEFT JOIN tb_user AS u ON o.user_id = u.id
LEFT JOIN tb_orderdetail AS d ON d.order_id = o.id
WHERE o.order_number = #{orderNumber}
</select>
</mapper>
测试:
@Test
public void findOrderAndOrderDetailByOrderNumber() {
Order order = userOrderMapper.findOrderAndOrderDetailByOrderNumber("20140921001");
System.out.println(order);
}
3 一对多+一对一查询
例:
四表连接 ,查询订单,查询出下单人的信息并且查询出订单详情中的商品数据
接口方法:
/**
* 查询订单,查询出下单人的信息并且查询出订单详情中的商品数据
* 一对多+一对一查询 四表连接
* @param orderNumber
* @return
*/
Order findOrderAndOrderDetailAndItemByOrderNumber(@Param("orderNumber") String orderNumber);
mapper.xml映射文件:
<mapper>
<resultMap id="orderUserDetailItemMap" type="Order" autoMapping="true">
<id column="id" property="id"/>
<association property="user" javaType="User" autoMapping="true">
<id column="user_id" property="id"/>
<result column="user_name" property="userName"/>
</association>
<collection property="orderDetailList" javaType="list" ofType="OrderDetail" autoMapping="true">
<id column="detail_id" property="id"/>
//在OrderDetail里加的一个Item类型属性
<association property="item" javaType="Item" autoMapping="true">
<id column="item_id" property="id"/>
<result column="item_name" property="itemName"/>
</association>
</collection>
</resultMap>
<select id="findOrderAndOrderDetailAndItemByOrderNumber" resultMap="orderUserDetailItemMap">
SELECT * ,d.id AS detail_id FROM tb_order AS o
LEFT JOIN tb_user AS u ON o.user_id = u.id
LEFT JOIN tb_orderdetail AS d ON d.order_id = o.id
LEFT JOIN tb_item AS i ON d.item_id = i.id
WHERE o.order_number = #{orderNumber}
</select>
</mapper>
测试:
@Test
public void findOrderAndOrderDetailAndItemByOrderNumber() {
Order order = userOrderMapper.findOrderAndOrderDetailAndItemByOrderNumber("20140921001");
System.out.println(order);//有:用户信息,订单信息,订单详情,商品详情
User user = order.getUser();
System.out.println(user);
List<OrderDetail> orderDetailList = order.getOrderDetailList();
for (OrderDetail orderDetail : orderDetailList){
System.out.println(orderDetail.getItem());//遍历出每个商品的详细信息
}
}
运行结果:
实体类pojo 总:
User
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class User {
private int id;
private String userName;//用户名
private String password;
private String name;//姓名
private int age;
private int sex;
private Date birthday;//出生日期
private Date created;//创建时间
private Date update;//更新时间
}
Order
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Order {
private int id;
private int userId;//外键用户id
private String orderNumber;//订单号
//将连表查询出来的是用户tb_user的信息封装到User中
private User user;
//将查询出来的订单详情封到集合中,一个订单有多个详情
private List<OrderDetail> orderDetailList ;
}
OrderDetail
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class OrderDetail {
private int id;
private int orderId;//订单号
private int itemId;//商品id
private Double totalPrice;//商品价格
private int status;//签收状态
//一个订单详情里有一个商品描述对应着商品的信息
private Item item;
}
Item
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Item {
private int id;
private String itemName;//商品名称
private Float itemPrice;//商品价格
private String itemDetail;//商品描述
}
4 resultMap继承
如图:
继承后可以实现代码的复用,这跟java中的继承类似,如果继承后想增加方法新的功能可以重写,如下例:虚线注释部分是没有继承之前的的写法,继承之后重复的代码可以省略掉。
mapper.xml映射文件
*******orderMap********
<resultMap id="orderMap" type="Order" autoMapping="true">
<id column="id" property="id"/>
<association property="user" javaType="User" autoMapping="true">
//<!--column用user_id是因为用id的话会和上边的id重,映射的时候不知道该是哪个,user_id是order里的外键同时也是user表里的id,值是一样的-->
<id column="user_id" property="id"/>
<result column="user_name" property="userName"/>
</association>
</resultMap>
*******OrderMapDetail********
<resultMap id="OrderMapDetail" type="Order" autoMapping="true" extends="orderMap">
<!-- /*<id column="id" property="id"/>
<association property="user" javaType="User" autoMapping="true">
<id column="user_id" property="id"/>
<result column="user_name" property="userName"/>
</association>*/-->
<collection property="orderDetailList" javaType="list" ofType="OrderDetail" autoMapping="true">
//<!--detail_id查询过取别名后的id,查询结果对应的列名是啥这就是啥-->
<id column="detail_id" property="id"/>
<result column="item_id" property="itemId"/>
</collection>
</resultMap>
************orderUserDetailItemMap***************
<resultMap id="orderUserDetailItemMap" type="Order" autoMapping="true" extends="OrderMapDetail">
<!-- /*<id column="id" property="id"/>
<association property="user" javaType="User" autoMapping="true">
<id column="user_id" property="id"/>
<result column="user_name" property="userName"/>
</association>*/-->
<collection property="orderDetailList" javaType="list" ofType="OrderDetail" autoMapping="true">
<!-- /*<id column="detail_id" property="id"/>
<id column="item_id" property="itemId"/>*/-->
<association property="item" javaType="Item" autoMapping="true">
<id column="item_id" property="id"/>
<result column="item_name" property="itemName"/>
</association>
</collection>
</resultMap>
5 高级查询整理
resutlType无法帮助我们自动的去完成映射,所以只有使用resultMap手动的进行映射
type 结果集对应的数据类型 id 唯一标识,被引用的时候,进行指定
//resutlType无法帮助我们自动的去完成映射,所以只有使用resultMap手动的进行映射
//type 结果集对应的数据类型 id 唯一标识,被引用的时候,进行指定
<resultMap type="Order" id="orderUserLazyResultMap">
//<!—定义pojo中的单个对象的 property 定义对象的属性名, javaType 属性的类型,
<association property="user" javaType="User" autoMapping="true">
<id column="" property=""/>
</association>
//<!— 如果属性是集合使用collection ,javaType 集合的类型,ofType 表示集中的存储的元素类型
<collection property="details" javaType="List" ofType="OrderDetail" autoMapping="true">
<id column="" property=""/>
</collection>
</resultMap>
八 、 分页插件
1 分页插件的好处:
2 Mybatis的plugin实现原理
分页插件原理:
mapper.xml映射文件发送sql语句,如果在mybatis-config.xml中配置了拦截器的话则会进行拦截,然后拦截器那边会加上limit ?,?, 从而实现了分页
3 使用PageHelper实现分页:
导入依赖:
//<!--pageHelper分页插件依赖-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>3.7.6</version>
</dependency>
<dependency>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
<version>0.9.1</version>
</dependency>
配置拦截器插件:
这个拦截器插件放在配置环境的上面
//<!--配置分页拦截器插件,注意顺序,得在配置环境之前-->
<plugins><!--//分页插件实现原理:配置拦截器拦截发送的sql语句,然后加上limit语句执行分页操作,用的时候只需要传参就行了-->
<plugin interceptor="com.github.pagehelper.PageHelper">
//<!--设置数据库 方言:dialect-->
<property name="dialect" value="mysql"/>
//<!--查询记录总数,加上这句话就行了,到时候调用对应的方法就可以查询到总记录数-->
<property name="rowBoundsWithCount" value="true"/>
</plugin>
</plugins>
<environments default="development">
</environments>
测试分页方法:
@Test
public void findAllUser(){
//调用PageHelper.startPage():给拦截器传进去你要查询的页数和一页要显示的条数,然后拦截器会自动拦截你发送的sql语句,
// 然后在你的sql语句后边加上limit ?,? ,两个问号分边代表起始查询位置和显示条数
//第一个参数pageNum:1(第几页) ; 第二个参数pageSize:3 (一页显示多少条数据)
PageHelper.startPage(1,3);
List<User> userList = userOrderMapper.findAllUser();
userList.forEach(System.out::println);
//new一个pageInfo<>(userList)然后传进去你查询的集合可以得到一个pageInfo对象,这个对象中有查询总页数,总记录数方法...等等
PageInfo<User> pageInfo = new PageInfo<>(userList);
System.out.println("总记录数:" + pageInfo.getTotal());
System.out.println("总页数:" + pageInfo.getPages());
System.out.println("查询数据:");
List<User> list = pageInfo.getList();
list.forEach(System.out::println);
}
九 、Mybatis 使用注解
备注:如果使用注解开发,xxmapper.xml映射文件可以不用书写,但是在mybatis-config.xml中<mapper resource="com.hisoft.dao"/>
扫描包还是得加。
例: 增加,查询 注:其他同理
接口方法:
import com.hisoft.pojo.Item;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
public interface ItemMapper {
@Select("select * from tb_item")
List<Item> findAllItem();
@Insert("insert into tb_item(item_name,item_price,item_detail) values (#{itemName},#{itemPrice},#{itemDetail})")
int saveItem(Item item);
}
测试:
@Test
public void findAllItem() {
List<Item> itemList = itemMapper.findAllItem();
itemList.forEach(System.out::println);
}
@Test
public void saveItem() {
Item item = new Item("红魔手机", 3699f, "红魔电竞手机");
int i = itemMapper.saveItem(item);
sqlSession.commit();
}
十 、mybatis和spring整合
1 需要依赖:
pom.xml
文件
<dependencies>
//<!--spring beans-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
//<!--soring core-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
//<!--spring context 注解-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
//<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
//<!--mybatis spring插件-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
//<!--lombok pojo注解-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
//<!--日志记录-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
//<!--测试包-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
//<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.6</version>
</dependency>
//<!--HikariCP连接池-->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>3.3.1</version>
</dependency>
//<!--spring jdbc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
</dependencies>
2 配置spring文件applicationContext.xml
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
//<!--映入外部properties文件-->
<context:property-placeholder location="classpath:db.properties"/>
//<!--配置数据源-->
<bean id="hikariDateSource" class="com.zaxxer.hikari.HikariDataSource">
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
<property name="driverClassName" value="${db.driver}"/>
<property name="jdbcUrl" value="${db.url}"/>
</bean>
//<!--配置sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
//<!--通过数据源-->
<property name="dataSource" ref="hikariDateSource"/>
//<!--引入mybatis的总配置-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
//<!--pojo别名扫描-->
<property name="typeAliasesPackage" value="com.hisoft.pojo"/>
//<!--引入mapper映射器文件-->
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
</bean>
//<!--配置mapper 批量扫描bao包,生成接口的实现类对象,并注入到Spring容器中-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.hisoft.dao"/>
</bean>
****************************************
//<!--配置mapper-->这种方式需要扫描包多的时候太麻烦了,不推荐使用
<bean id="itemMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
//<!--配置Mapper接口-->
<property name="mapperInterface" value="com.hisoft.dao.ItemMapper"/>
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
</beans>
配置连接池(c3p0)
//引入外部properties文件
<context:property-placeholder location="classpath:db.properties"/>
//<!-- 配置连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="${c3p0.driverClass}"></property>
<property name="jdbcUrl" value="${c3p0.url}"></property>
<property name="user" value="${c3p0.user}"></property>
<property name="password" value="${c3p0.password}"></property>
</bean>
配置SqlSessionFactory
//<!-- 配置SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
//<!--引入mybatis的总配置 -->
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
</bean>
配置mapper
//<!-- 配置mapper -->
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
//<!-- 配置mapper接口 (这种方式太麻烦)-->
<property name="mapperInterface" value="cn.hisoft.mybatis.mapper.UserMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
配置mapper接口扫描器
//<!-- 配置mybatis mapper接口扫描器 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
//<!-- 如果配置多个mapper的路径,可以使用,多个包使用逗号分割即可: value="cn.hisoft.mybatis.mapper,cn.hisoft.mybatis.mapper" -->
<property name="basePackage" value="com.hisoft.dao.mapper" />
</bean>
3 spring注解单元测试
导入依赖:
//<!--单元格测试依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.9.RELEASE</version>
<scope>test</scope>
</dependency>
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
//获取applicationContext.xml配置文件
@ContextConfiguration(locations = "classpath:applicationContext.xml")
@RunWith(SpringJUnit4ClassRunner.class)//开启单元测试
public class ItemMapperTest {
@Autowired
private ItemService itemService;
@Test
public void findAllItem() {
List<Item> allItem = itemService.findAllItem();
allItem.forEach(System.out::println);
}
@Test
public void saveItem() {
Item item = new Item("三星",2999f,"三星手机");
int count = itemService.saveItem(item);
System.out.println(count);
}
}
十一 、spring管理事务
1,编程式事务:编码复杂,不利于后期维护
2 、声明式事务,运用aop编程思想,统一配置,从业务代码中分离出来,不能实现细粒度的事务管理
声明式事务:
1 事务的传播行为
即然是传播,那么至少有两个东西,才可以发生传播。单体不存在传播这个行为。
事务传播行为(propagation behavior)指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行。
例如:methodA事务方法调用methodB事务方法时,methodB是继续在调用者methodA的事务中运行呢,还是为自己开启一个新事务运行,这就是由methodB的事务传播行为决定的。
Spring定义了七种传播行为:
2 Spring事务的隔离级别
事务特征:
⑴ 原子性(Atomicity)
原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,这和前面两篇博客介绍事务的功能是一样的概念,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。
⑵ 一致性(Consistency)
一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。
⑶ 隔离性(Isolation)
隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。
关于事务的隔离性数据库提供了多种隔离级别,稍后会介绍到。
⑷ 持久性(Durability)
持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
例如我们在使用JDBC操作数据库时,在提交事务方法后,提示用户事务操作完成,当我们程序执行完成直到看到提示后,就可以认定事务以及正确提交,即使这时候数据库出现了问题,也必须要将我们的事务完全执行完成,否则就会造成我们看到提示事务处理完毕,但是数据库因为故障而没有执行事务的重大错误。
场景:
同一个事务内(同一个服务内)
事务隔离级
:
1.
READ UNCOMMITTED
(读未提交数据
):允许事务读取未被其他事务提交的变更数据,会出现脏读、不可重复读和幻读问题。
2.
READ COMMITTED
(读已提交数据
):只允许事务读取已经被其他事务提交的变更数据,可避免脏读,仍会出现不可重复读和幻读问题。
3.
REPEATABLE READ
(可重复读
):确保事务可以多次从一个字段中读取相同的值,在此事务持续期间,禁止其他事务对此字段的更新,可以避免脏读和不可重复读,仍会出现幻读问题。
4.
SERIALIZABLE
(序列化
):确保事务可以从一个表中读取相同的行,在这个事务持续期间,禁止其他事务对该表执行插入、更新和删除操作,可避免所有并发问题,但性能非常低。
3 运用aop编程思想声明事务管理配置文件
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd">
//<!--声明式事务-->
//<!--配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
//<!--引入数据源-->
<property name="dataSource" ref="hikariDateSource"/>
</bean>
//<!--配置事务切面-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
//<!--save开头的函数名,name规定方法 ,isolation:设置隔离级别,默认级别为DEFAULT propagation:传播行为-->
<tx:attributes>
<tx:method name="save*" read-only="false" isolation="DEFAULT" propagation="REQUIRED"/>
<tx:method name="update*" read-only="false" isolation="DEFAULT" propagation="REQUIRED"/>
<tx:method name="add*" read-only="false" isolation="DEFAULT" propagation="REQUIRED"/>
<tx:method name="delete*" read-only="false" isolation="DEFAULT" propagation="REQUIRED"/>
<tx:method name="*" read-only="true" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
//<!--切面织入-->
<aop:config>
//<!--切入点,书写切入点表达式-->
<aop:pointcut id="aopPointcut" expression="execution(* com.hisoft.service.*.*(..))"/>
//<!--把事务和切入点联系起来-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="aopPointcut"/>
</aop:config>
需要依赖:
//<!--事务-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
//<!--spring-aop切面,得配合着aspectjweaver依赖使用-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
//<!--aspectJ注解 @Aspect-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
4 开启注解管理事务
//<!--声明式事务-->
//<!--配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
//<!--引入数据源-->
<property name="dataSource" ref="hikariDateSource"/>
</bean>
// <!--开启基于注解的事务管理-->
<tx:annotation-driven transaction-manager="transactionManager"/>
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional
public class ItemServiceImpl implements ItemService {
@Autowired
private ItemMapper itemMapper;
@Override//可以配置传播属性,隔离级别,指定回滚
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT,rollbackFor = Exception.class)
public int saveItem(Item item) {
int i = itemMapper.saveItem(item);
return i;
}
@Override
@Transactional(isolation = Isolation.DEFAULT,readOnly = true)
public void deleteItemById(int id) {
itemMapper.deleteItemById(id);
}
}
十二 、 SSM整合
1 applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd">
//<!--开启注解-->
<context:component-scan base-package="com.hisoft"/>
//<!--映入外部properties文件-->
<context:property-placeholder location="classpath:db.properties"/>
//<!--配置数据源-->
<bean id="hikariDateSource" class="com.zaxxer.hikari.HikariDataSource">
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
<property name="driverClassName" value="${db.driver}"/>
<property name="jdbcUrl" value="${db.url}"/>
</bean>
//<!--配置sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
//<!--通过数据源-->
<property name="dataSource" ref="hikariDateSource"/>
//<!--引入mybatis的总配置-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
//<!--pojo别名扫描-->
<property name="typeAliasesPackage" value="com.hisoft.pojo"/>
//<!--引入映射器文件-->
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
</bean>
<!--配置mapper 批量扫描bao包,生成接口的实现类对象,并注入到Spring容器中-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.hisoft.dao"/>
</bean>
// <!--声明式事务-->
//<!--配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
//<!--引入数据源-->
<property name="dataSource" ref="hikariDateSource"/>
</bean>
//<!--开启基于注解的事务管理-->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
2 web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
//<!--配置spring ioc容器-->
<context-param>//配置监听器,监听启动web容器时自动加载applicationContext的配置信息
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
//<!--在servlet初始化之前引导根web应用程序上下文,springMVC整合 listener:监听器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
//<!--配置springMVC前置控制器-->
<servlet>
<servlet-name>mvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
//classpath:mvc-servlet.xml:请求视图解析器解析视图
<param-value>classpath:mvc-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
//<!--spring 字符集过滤器-->
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
3 mvc-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--开启controller扫描-->
<context:component-scan base-package="com.hisoft.controller"/>
<!--开启注解-->
<mvc:annotation-driven/>
//<!--配置视图解析器-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
<mvc:resource mapping="/static/**" localtion="/static/" />
</beans>
4 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="LOG4J"/>
//<!--开启驼峰命名-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
//<!--resultType类型别名扫描-->
<typeAliases>
<package name="com.hisoft.pojo"/>
</typeAliases>
</configuration>