Mybatis框架

MyBatis框架

一、常用的几种框架

1.Mybatis  半自动化ORM框架    (hibernate全自动框架)

- Mybatis Plus

 

2.Spring   SSM,SSH都离不开Spring

3.SpringMVC

4.SpringBoot

5.SpringCloud

6.Dubbo

 

 

 

 

 

 

二、Mybatis开篇

1.持久化和ORM

持久化:代表的数据从瞬时状态转换为持久状态的过程

ORM:对象关系映射,说白了就是程序实体与数据库二维表的字段映射,如果实体属性和表中字段一致,会自动将数据封装,如果不一致也有手动映射的方式

 

2.什么是半自动化?

不是全部有框架来完成工作,SQL有程序员自己编译,要求较高的SQL基础,

3.搭建Mybatis开发环境

步骤一:导入Mybatis依赖,数据库依赖

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->

        <dependency>

            <groupId>org.mybatis</groupId>

            <artifactId>mybatis</artifactId>

            <version>3.4.6</version>

        </dependency> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->

        <dependency>

            <groupId>mysql</groupId>

            <artifactId>mysql-connector-java</artifactId>

            <version>5.1.38</version>

        </dependency>

 

步骤二:创建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>

<!--加载配置文件-->

 <properties resource="datasource.properties"></properties>

 

<!--defauilt代表默认情况下-->

<environments default="development">

<!--环境:可以有多套-->

<environment id="development">

<!--事务管理采用JDBC,需要程序员手动提交事务,否则数据会出现脏数据   type还可以取值为managerd 什么都不管-->

<transactionManager type="JDBC"/>

<!--数据源  type取值默认为pooled连接池,还可以采用unpooled 还有 JNDI方式-->

<dataSource type="POOLED">

<!--driver代表数据库驱动-->

<property name="driver" value="${jdbc.driver}"/>

<property name="url" value="${jdbc.url}"/>

<property name="username" value="${jdbc.username}"/>

<property name="password" value="${jdbc.password}"/>

</dataSource>

</environment>

 

</environments>

<!--小配置文件映射集合,之前我们采用Dao层实现类编写SQL处理数据,学习了Mybatis就是一个Dao层接口对应一个小配置 文件, SQL放入到配置文件当中-->

<mappers>

<!--单独的小配置文件加载-->

<!--<mapper resource="com/wdksoft/dao/UserMapper.xml"/>-->

<!--小配置文件所在包名-->

<package name="com.wdksoft.dao"/>

</mappers>

</configuration>

 

步骤三:创建实体

步骤四:创建Dao层接口和小配置文件

public interface INewsUsersDao {

//查询所有用户信息

public List<News_Users> getAllUser() throws Exception;

}

 

小配置文件需要与Dao层接口相同名称,

<?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代表命名空间,指定小配置文件所关联的Dao层接口位置-->

<mapper namespace="com.wdksoft.dao.INewsUsersDao">

<!--查询所有员工记录 id代表方法名字  resultType代表返回类型  -->

<select id="getAllUser" resultType="com.wdksoft.entity.News_Users">

select * from news_users

</select>

</mapper>

默认情况下不会扫描java下的xml文件,所以解决方案为在pom.xml文件中加入节点扫描

<resources>

<resource>

<directory>src/main/java</directory>

<includes>

<include>**/*.xml</include>

</includes>

</resource>

</resources>

步骤五:测试

//加载配置文件,以流的形式

 

 

 

//通过SqlSessionFactoryBuilder来获取工厂.build(is)

 

 

 

//通过工厂获取SqlSession

 

factory.openSession();

 

 

public static void main(String[] args) throws IOException {

//最终终极目的获取到SqlSession对象,因为该对象提供增伤改查方法

 

//步骤一:创建输入流,加载配置文件

InputStream is = Resources.getResourceAsStream("mybatis-config.xml");

//步骤二:通过SqlSessionFactoryBuilder获取SqlSessionFactory工长

SqlSessionFactory build = new SqlSessionFactoryBuilder().build(is);

//步骤三:通过工厂创建SqlSession对象

SqlSession sqlSession = build.openSession();

 

//步骤四:执行增删改查

List<News_Users> userList = sqlSession.selectList("getAllUser");

for(News_Users user:userList){

System.out.println(user.toString());

}

//最后一步:关闭资源

sqlSession.close();

}

 

4.别名使用

在大配置文件中,添加配置

<!--配置别名-->

    <typeAliases>

        <!--配置单独别名,默认规则时以实体命名-->

       <!-- <typeAlias type="com.wdksoft.entity.News_Users" alias="User"/>-->

        <!--全局配置采用实体命名-->

        <package name="com.wdksoft.entity"/>

    </typeAliases>

 

小配置使用实体名称即可

 

 

5.集成Log4j

1.Log4j的配置文件添加到环境当中

2.需要引入log4j依赖

3.Mybatis大配置文件中引用Log4j

<settings>

<setting name="logImpl" value="LOG4J"/>

</settings>

 

6.GetMapper定位到具体接口

INewsUsersDao mapper = sqlSession.getMapper(INewsUsersDao.class);

        List<News_Users> allUser = mapper.getAllUser();

        for(News_Users user:allUser){

            System.out.println(user.toString());

        }

三、Mybatis增删改查

1添加数据

步骤一:在接口中新建方法

//添加数据

public int addUser(News_Users users) throws Exception;

步骤二:在下配置文件中加入SQL

<!--添加数据-->

<insert id="addUser">

<!--#{}可以获取到基本数据类型的变量名,也可以获取负责数据类型中的属性名-->

insert into news_users(uname,upwd,telephone,email) values(#{uname},#{upwd},#{telephone},#{email})

</insert>

步骤三:测试,手动提交

@Test

public void insert() throws Exception {

//步骤一:将配置文件以流的形式加载

InputStream is = Resources.getResourceAsStream("mybatis-config.xml");

//步骤二:创建SqlSessionFactory工厂

SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);

//步骤三:获取SqlSession对象

SqlSession sqlSession = factory.openSession();

//步骤四:获取接口类型

INewsUsersDao iNewsUsersDao = sqlSession.getMapper(INewsUsersDao.class);

 

News_Users users=new News_Users();

users.setUname("chaiyingjie");

users.setUpwd("pwd@123");

users.setTelephone("13888888888");

users.setEmail("123@qq.com");

int count = iNewsUsersDao.addUser(users);

 

if(count>0){

System.out.println("添加成功~");

}else{

System.out.println("添加失败~");

}

 

//增伤改需要手动提交,SqlSession底层调用的还是transaction事务对象提交事务

sqlSession.commit(true);

 

//步骤五:关闭资源

sqlSession.close();

}

 

提示:

#{}表示一个占位符号 通过#{}可以实现 preparedStatement 向占位符中设置值,自动进行 java 类型和 jdbc 类型 转换, #{}可以有效防止 sql 注入。 #{}可以接收简单类型值或 pojo 属性值。 如果 parameterType 传输单个简单类型值,#{}括号中可以是 value 或其它名称。 ${}表示拼接 sql 串 通过${}可以将 parameterType 传入的内容拼接在 sql 中且不进行 jdbc 类型转换, 可以接 收简单类型值或 pojo 属性值,如果 parameterType 传输单个简单类型值, {}可以接收简单 类型值或 pojo 属性值,如果 parameterType 传输单个简单类型值,可以接收简单类型值或 pojo 属性值,如果 parameterType 传输单个简单类型值,{}括号中只能是 value

 

 

 

 

2Mybaits修改案例

步骤一:在接口中新建方法

//修改数据

public int updateUser(News_Users users) throws Exception;

步骤二:配置小配置文件

<!--修改数据-->

<update id="updateUser">

update news_users set uname=#{uname},upwd=#{upwd} where uid=#{uid}

</update>

步骤三:测试

@Test

public void update() throws Exception {

//步骤一:将配置文件以流的形式加载

InputStream is = Resources.getResourceAsStream("mybatis-config.xml");

//步骤二:创建SqlSessionFactory工厂

SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);

//步骤三:获取SqlSession对象

SqlSession sqlSession = factory.openSession();

//步骤四:获取接口类型

INewsUsersDao iNewsUsersDao = sqlSession.getMapper(INewsUsersDao.class);

 

News_Users users=new News_Users();

users.setUname("yiming");

users.setUpwd("123456");

users.setUid(8);

 

int count = iNewsUsersDao.updateUser(users);

System.out.println(count);

//增伤改需要手动提交,SqlSession底层调用的还是transaction事务对象提交事务

sqlSession.commit(true);

 

//步骤五:关闭资源

sqlSession.close();

}

 

3Mybatis删除案例

步骤一:在接口中新建方法

//删除数据

public int deleteUser(Integer uid) throws Exception;

步骤二:配置小配置文件

 <!--删除数据-->

<delete id="deleteUser">

delete from news_users where uid=#{uid}

</delete>

步骤三:测试

@Test

public void delete() throws Exception {

//步骤一:将配置文件以流的形式加载

InputStream is = Resources.getResourceAsStream("mybatis-config.xml");

//步骤二:创建SqlSessionFactory工厂

SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);

//步骤三:获取SqlSession对象

SqlSession sqlSession = factory.openSession();

//步骤四:获取接口类型

INewsUsersDao iNewsUsersDao = sqlSession.getMapper(INewsUsersDao.class);

 

int count = iNewsUsersDao.deleteUser(10);

System.out.println(count);

//增伤改需要手动提交,SqlSession底层调用的还是transaction事务对象提交事务

sqlSession.commit(true);

 

//步骤五:关闭资源

sqlSession.close();

}

4添加数据返回主键三种方案

第一种在insert标签内加入useGeneratedKeys代表开启JDBC生成主键      keyProperty代表实体主键属性名称

<insert id="addUser" useGeneratedKeys="true" keyProperty="uid">

insert into news_users(uname,upwd,telephone,email) values(#{uname},#{upwd},#{telephone},#{email})

</insert>

第二种在insert语句后查询最后一次添加数据主键的id

<selectKey keyProperty="uid" resultType="java.lang.Integer">

            SELECT LAST_INSERT_ID() AS UID

            

        </selectKey>

 

 

第三种与第二种类似,查询主键全局变量

<selectKey keyProperty="uid" resultType="java.lang.Integer">

            SELECT @@IDENTITY AS UID

        </selectKey>

 

5自动映射和ResultMap的使用

Mybatis默认是自动映射的,只要实体的属性和数据库字段一致就可以自动映射

当实体和数据库二维表不一致的情况下,或者是在关联查询的场景下我们使用resultMap

<!--resultMap结果映射,在多表连接查询时,在实体与数据库二维表字段不一致时   id代表resultMap结果的唯一标识    type 代表实体的类型-->

<resultMap id="userMap" type="News_Users">

<!--result标签代表普通字段       property代表的是实体中的属性          column代表数据库二维表中字段-->

<result property="phone" column="telephone"/>

</resultMap>

 

<select id="getAllUser" resultMap="userMap">

select * from news_users

</select>

 

 

取消全局映射:在Mybatis大配置文件中settings节点下加入autoMappingBehavior属性 属性值默认取值为PARTIAL代表只映射自己,在关联查询时不会映射其他实体数据     NONE代表取消映射    FULL所有都能映射

 

取消局部映射,在小配置文件的resultMap节点中加入autoMapping属性值为false,默认为true,关闭了映射之后所有的字段如果没有在resultMap手动映射,则取值为null

 

 

6MybatisUtil工具类提炼

核心思想,利用静态代码块先创建出工厂,然后再获取SqlSession的方法内通过工厂获取对象  

public class MybatisUtil {

static String resourcePath="mybatis-config.xml";

static InputStream is = null;

static SqlSessionFactory factory = null;

static {

try {

is = Resources.getResourceAsStream(resourcePath);

//获取工厂

factory = new SqlSessionFactoryBuilder().build(is);

} catch (IOException e) {

e.printStackTrace();

}

}

 

//获取SqlSession对象

public static SqlSession getSqlSession(){

return factory.openSession();

}

 

//关闭SqlSession对象

public static void closeSqlSession(SqlSession session){

session.close();

}

}

 

7调用测试:

public static void main(String[] args) throws Exception {

SqlSession sqlSession = MybatisUtil.getSqlSession();

 

//步骤四:执行增删改查

INewsUsersDao mapper = sqlSession.getMapper(INewsUsersDao.class);

List<News_Users> allUser = mapper.getAllUser();

for(News_Users user:allUser){

System.out.println(user.toString());

}

 

MybatisUtil.closeSqlSession(sqlSession);

 

}

 

三、模糊查询

<!--模糊查询-->

<select id="getLikeUser" resultType="News_Users">

 

1<!--使用#{}-->

<!--select * from news_users where uname like '%' #{uname} '%'-->

 

2<!--使用concat字符串拼接-->

select * from news_users where uname like concat('%',#{uname},'%')

 

3<!--${}不能防止SQL注入,而且必须加@Param指定参数-->

<!--select * from news_users where uname like '%${uname}%'-->

   </select>

 

 

四、多条件查询

1、使用@Param

当零散参数时,没有办法根据默认参数名进行装配,所以可以使用@Param指定名字

public List<News_Users> getUser(@Param("uname") String uname,@Param("email") String email) throws Exception;

<select id="getUser" resultType="News_Users">

select * from news_users where uname=#{uname} and email=#{email}

</select>

 

2、使用Map集合

将零散参数装配到map集合当中,但是注意map集合的key需要和小配置文件应用属性名称保持一致

public List<News_Users> getUserForMap(Map<String,Object> map) throws Exception;

 

小配置:

<select id="getUser" resultType="News_Users">

select * from news_users where uname=#{uname} and email=#{email}

</select>

测试类:

//将多条件封装到Map集合当中

Map<String,Object> map=new HashMap<>();

//key需要与小配置文件的参数名称一致

map.put("uname","chaiyingjie");

map.put("email","123@qq.com");*/

 

    List<News_Users> userList = mapper.getUserForMap(map);

for (News_Users userItem:userList) {

System.out.println(userItem.toString());

}

 

3、使用下标

需要使用小标指定参数位置,arg小标(从0开始)

public List<News_Users> getUserFroIndex(String uname,String email) throws Exception;

 

小配置文件:

<select id="getUserFroIndex" resultType="News_Users">

select * from news_users where uname=#{arg0} and email=#{arg1}

</select>

五、智能标签,动态SQL

1、where智能标签

识别第一个and或者or关键字,变为where

 

2if智能标签

可以动态判断条件,动态拼接SQL

 

3.whereif实现动态条件判断案例

//动态查询,用户可以随意组合条件,可以根据标题模糊查询,也可以根据分类查询

public List<News> getNews(@Param("ntitle") String ntitle, @Param("ntid") Integer ntid) throws Exception;

 

小配置文件:

<select id="getNews" resultType="News">

select * from news

<!--加入where,会将第一个and或者or变为where-->

<where>

<!--ntitle不用加#{}     并且用and   或者用or-->

<if test="ntitle!=null and ntitle!=''">

and ntitle like concat('%',#{ntitle},'%')

</if>

<if test="ntid!=0">

and ntid=#{ntid}

</if>

</where>

</select>

 

测试类:

@Test

public void getNewsData() throws Exception {

//获取SqlSession对象

SqlSession sqlSession = MybatisUtil.getSqlSession();

 

INewsMapper mapper = sqlSession.getMapper(INewsMapper.class);

List<News> newsList = mapper.getNews("", 4);

for(News news:newsList){

System.out.println(news.toString());

}

 

//关闭资源

MybatisUtil.closeSqlSession(sqlSession);

}

4Choose

可以用于多条件判断,使用whenif相同。其他情况也已使用otherwise,只能执行一个

//查询新闻数据,如果用户指定新闻分类则查询特定新闻分类数据,如果没有指定,默认新闻分类为1

public List<News> getNewsByNtid(@Param("ntid") Integer ntid) throws Exception;

 

小配置文件:

<select id="getNewsByNtid" resultType="News">

select * from news

<where>

<choose>

<!--可以使用when条件判断-->

<when test="ntid!=0">

and ntid=#{ntid}

</when>

<!--否则情况-->

<otherwise>

and ntid=1

</otherwise>

</choose>

</where>

</select>

 

测试类:

@Test

public void getNewsByNtid() throws Exception {

//获取SqlSession对象

SqlSession sqlSession = MybatisUtil.getSqlSession();

 

INewsMapper mapper = sqlSession.getMapper(INewsMapper.class);

List<News> newsList = mapper.getNewsByNtid(4);

for(News news:newsList){

System.out.println(news.toString());

}

 

//关闭资源

MybatisUtil.closeSqlSession(sqlSession);

}

 

5Set标签

主要用于修改,可以加入set关键字,也能忽略最后一个,

 //动态修改

public int updateNews(@Param("ntitle") String ntitle,@Param("ntid") Integer ntid,@Param("nid")Integer nid) throws Exception;

 

 

 

<!--动态修改-->

<update id="updateNews">

update news

<!--给第一个参数前加入set关键字,能够忽略最后一个,-->

<set>

<if test="ntitle!=null and ntitle!=''">

ntitle=#{ntitle},

</if>

<if test="ntid!=0">

ntid=#{ntid},

</if>

</set>

where nid=#{nid}

</update>

 

 

 

@Test

public void updateNews() throws Exception {

//获取SqlSession对象

SqlSession sqlSession = MybatisUtil.getSqlSession();

 

INewsMapper mapper = sqlSession.getMapper(INewsMapper.class);

 

int count = mapper.updateNews("新管状病毒", 4, 170);

System.out.println(count);

 

 

sqlSession.commit();

//update news where nid=170

//关闭资源

MybatisUtil.closeSqlSession(sqlSession);

}

 

6Trim

可以加入前缀和后缀,也可以替换,删除前缀后缀

Prefix:在结果前加入一个前缀 PrefixOverrides:替换或者覆盖或者删除掉前缀 Suffix:在结果后加入一个后缀 SuffixOverrides:替换或者覆盖或者删除掉后缀

 

 

1.使用Trim更改where动态条件拼接

<select id="getNews" resultType="News">

select * from news

<!--trim  prefix代表添加一个前缀  prefixOverridesand|or替换 只替换第一个-->

<trim prefix="where" prefixOverrides="AND|OR">

<!--ntitle不用加#{}     并且用and   或者用or-->

<if test="ntitle!=null and ntitle!=''">

and ntitle like concat('%',#{ntitle},'%')

</if>

<if test="ntid!=0">

and ntid=#{ntid}

</if>

</trim>

</select>

 

2.替代set

<update id="updateNews">

update news

<!--给第一个参数前加入set关键字,能够忽略最后一个,-->

<trim prefix="set" suffixOverrides=",">

<if test="ntitle!=null and ntitle!=''">

ntitle=#{ntitle},

</if>

<if test="ntid!=0">

ntid=#{ntid},

</if>

</trim>

where nid=#{nid}

</update>

7Foreach

可以遍历集合或者数组

 //查询发布新闻作者为sprotnews的新闻

public List<News> getNewsByAuthor(@Param("authors") String [] authors) throws Exception;

 

<select id="getNewsByAuthor" resultType="news">

select * from news where nauthor in

<!--collection代表数组/集合 也能代表名称(需要@Param指定名称) open代表前缀    close代表后缀   separator每一项分隔符   item代表当前项 -->

<foreach collection="authors" open="(" close=")" separator="," item="author">

#{author}

</foreach>

</select>

 

@Test

public void getNewsByAuthor() throws Exception {

//获取SqlSession对象

SqlSession sqlSession = MybatisUtil.getSqlSession();

 

INewsMapper mapper = sqlSession.getMapper(INewsMapper.class);

 

List<News> newsByAuthor = mapper.getNewsByAuthor(new String[]{"sport", "news"});

for(News item:newsByAuthor){

System.out.println(item.toString());

}

 

//update news where nid=170

//关闭资源

MybatisUtil.closeSqlSession(sqlSession);

}

8查询列的引用

<sql id="news">

nid,ntitle,ncreateDate,ncontent

</sql>

 

<select id="getNews" resultType="News">

select <include refid="news"/> from news

<!--trim  prefix代表添加一个前缀  prefixOverridesand|or替换 只替换第一个-->

<trim prefix="where" prefixOverrides="AND|OR">

<!--ntitle不用加#{}     并且用and   或者用or-->

<if test="ntitle!=null and ntitle!=''">

and ntitle like concat('%',#{ntitle},'%')

</if>

<if test="ntid!=0">

and ntid=#{ntid}

</if>

</trim>

</select>

 

3多对一

查询所有的新闻,包含新闻的分类

单条SQL:

mapper接口层:

//查询所有新闻数据

public List<News> getAllNews() throws Exception;

 

小配置文件:

<resultMap id="newsMap" type="News">

自动关联的情况下,只要保证实体属性和数据表字段一致即可

 

关联映射一的一方  property实体中关联一的一方的属性

<association property="topic" javaType="Topic">

<!–配置关联的属性,写实体与表不一致的字段–>

 

</association>

</resultMap>

<select id="getAllNews" resultMap="newsMap">

select * from news,topic where news.ntid=topic.tid

</select>

 

测试类:

/**

 * 多对一

 * @throws Exception

 */

@Test

public void getAllNews() throws Exception {

//获取SqlSession对象

SqlSession sqlSession = MybatisUtil.getSqlSession();

 

INewsMapper mapper = sqlSession.getMapper(INewsMapper.class);

List<News> newsList = mapper.getAllNews();

for(News news:newsList){

System.out.println(news.toString());

}

//关闭资源

MybatisUtil.closeSqlSession(sqlSession);

}

 

多条SQL

mapper接口层:

//查询所有新闻数据

public List<News> getAllNews() throws Exception;

 

小配置文件:

<resultMap id="newsMap" type="News">

<!--植入一的一方的对象-->

<association property="topic" javaType="Topic" select="getTopicByNtid" column="ntid"></association>

</resultMap>

 

<select id="getAllNews" resultMap="newsMap">

select * from news

</select>

<select id="getTopicByNtid" resultType="Topic">

select * from topic where tid=#{ntid}

</select>

 

测试类:

/**

 * 多对一

 * @throws Exception

 */

@Test

public void getAllNews() throws Exception {

//获取SqlSession对象

SqlSession sqlSession = MybatisUtil.getSqlSession();

 

INewsMapper mapper = sqlSession.getMapper(INewsMapper.class);

List<News> newsList = mapper.getAllNews();

for(News news:newsList){

System.out.println(news.toString());

}

//关闭资源

MybatisUtil.closeSqlSession(sqlSession);

}

4多对多

一对多成立,反之多对一也成立

一名教员可以教授多名学员,多名教员可以教授一名学员

 

Student

List<Teacher>

Teacher

List<Student>

 

解决方案:在实体当中互相植入多的一方的对象(如果利用到了第三章表,返回的结果是多条记录,那就不能采用单个对象接收数据,要采用集合)

mapper层接口

//查询微冷的雨教授的学员

public List<Teacher> getTeacherById(Integer tid) throws Exception;

 

mapper小配置文件

<resultMap id="teacherMap" type="Teacher">

<!--植入多的一方的对象-->

<collection property="stuList" ofType="Student">

 

</collection>

</resultMap>

<select id="getTeacherById" resultMap="teacherMap">

select * from teacher,student,t_s_relation where teacher.tid=t_s_relation.tid and student.stuid=t_s_relation.stuid

and teacher.tid=#{tid} and t_s_relation.tid=#{tid}

</select>

 

 

测试类:

@Test

public void getTeacherById() throws Exception {

//获取SqlSession对象

SqlSession sqlSession = MybatisUtil.getSqlSession();

 

ITeacherMapper mapper = sqlSession.getMapper(ITeacherMapper.class);

List<Teacher> teacherList = mapper.getTeacherById(2);

for (Teacher teacher:teacherList){

System.out.println(teacher.toString());

}

 

//关闭资源

MybatisUtil.closeSqlSession(sqlSession);

}

 

 

5自关联

在自身内部关联自身集合

实体类:

public class City {

private Integer cid;    //地区编号

private String cname;   //地区名称

private Integer parentid;    //上一级分类ID

//自关联,就是在内部注入本身类型的集合

private List<City> cityList;

}

mapper层接口

//北京市下面的所有城区

public City getCity(Integer cid) throws Exception;

 

小配置文件

<resultMap id="cityMap" type="City">

<id property="cid" column="cid"/>

<collection property="cityList" ofType="City" select="getChildCity" column="cid">

 

</collection>

</resultMap>

<!--自关联怎么样去查询-->

<select id="getCity" resultMap="cityMap">

select * from city where cid=#{cid}

</select>

<select id="getChildCity" resultMap="cityMap">

select * from city where parentid=#{cid}

</select>

 

测试类:

@Test

public void getCity() throws Exception {

//获取SqlSession对象

SqlSession sqlSession = MybatisUtil.getSqlSession();

 

ICityMapper mapper = sqlSession.getMapper(ICityMapper.class);

City city = mapper.getCity(1);

System.out.println(city.toString());

 

//关闭资源

MybatisUtil.closeSqlSession(sqlSession);

}

 

 

八、延迟加载

称为懒加载,可以控制加载的方式,主要用于关联查询数据上,可以减轻数据库服务器压力,Mybatis默认不开启延迟加载

延迟加载时机:

1直接加载

在执行Select查询出主加载对象数据完毕后,直接执行关联对象的查询

2侵入式延迟加载

先执行主加载对象的查询,不会立马执行关联对象的查询,当调用主加载对象的属性时才会执行关联查询

3深度延迟

先执行主加载对象的查询,不会立马执行关联对象查询,当调用关联对象的属性才会执行关联查询

4延迟加载配置过程

1.开启延迟加载:在大配置文件中添加LazyLodingEnabled属性值为true,默认为false代表不开启延迟加载,如果开启延迟加载不配置延迟加载方式,默认为深度

2.开启侵入式延迟加载:在大配置文件中,配置延迟加载方式,添加aggressiveLazyLoading属性,true代表的是侵入式延迟加载,false代表的是深度延迟加载

3.4.1版本包括版本以前默认是ture代表侵入式延迟加载,在版本以后默认值为false代表深度延迟

 

<settings>

<!--开启延迟加载-->

<setting name="lazyLoadingEnabled" value="true"/>

<!--配置侵入式延迟加载,如果不手动配置,默认为深度延迟

 aggressiveLazyLoading 默认值为false代表默认执行深度延迟

 -->

<setting name="aggressiveLazyLoading" value="false"/>

</settings>

 

 

九、缓存

1一级缓存

默认是开启一级缓存,所在的范围SqlSession范围,只要SqlSession没有关闭,那么缓存中的数据仍然有效

缓存说明:缓存是根据namespace进行划分的,不同的namespace缓存数据相互不干扰,缓存是为了减轻数据库服务器的压力,也就是说相同的查询只需要第一次执行数据库

2一级缓存证明

统一个SqlSession范围内,无论创建多少个Mapper对象,只要第一次查询时将对应数据放到缓存中,后续再次读取该数据时执行得都是缓存

 

增删改会不会对以及缓存有影响:增删改会清空以及缓存数据,从新执行数据库查询,但是如果没有commit数据,请各位同学注意,可能会产生脏数据

 

3一级缓存结论

1.Mybatis默认开启一级缓存,作用域为SqlSession,统一个SqlSession查询相同数据缓存生效

2.缓存查询依据:根据namespace+SqlIDSql语句本身,如果发现都相同走缓存,不同走查询

3.增删改会清空一级缓存,但是不要忘了commit,否则会出现脏数据

 

 

 

 

 

 

3、二级缓存

需要对象实现序列化

需要手动开启,所在的范围与整个应用程序相同,与SqlSession无关

开启二级缓存方式:

1.大配置文件中开启二级缓存

<!--配置日志-->

<settings>

<!--开启二级缓存-->

<setting name="cacheEnabled" value="true"/>

</settings>

 

2.小配置文件开启缓存

<cache/>

 

 

增删改对二级缓存影响:

如果commit会重新刷新二缓数据,执行数据库查询,如果没有commit则不刷新走缓存数据

 

 

关闭刷新缓存:默认情况下增删改只要提交,那么就会清空缓存,重新查询数据库    可以关闭刷新缓存,这样在提交时就不回重新刷新缓存数据,但是会出现脏数据

1.增删改可以关闭刷新缓存

flushCache用在增删改时,默认值为true代表刷新缓存,如果用在查询默认值为false代表读取缓存中数据

<!--flushCache代表刷新缓存,false为不刷新,也就是说在增删改提交数据后,还是会走缓存,不重新发送SQL-->

<insert id="addTeacher" flushCache="false">

insert into teacher(tname) values (#{tname})

</insert>

 

 

查询不应用缓存:

useCache用在查询时,默认值为true代表的应用缓存    false代表不应用缓存,每一次都发SQL

<select id="getAllTeacher" resultMap="teacherMap" useCache="false">

<!--select * from teacher,student,t_s_relation where teacher.tid=t_s_relation.tid and student.stuid=t_s_relation.stuid-->

select * from teacher

</select>

 

 

4、Mybatis整合第三方缓存Ehcache

需要开启二缓,依赖于二缓

1.导入依赖   ehcache   mybatis-ehcache

 

2.配置二级缓存策略,使用Ehcache第三方缓存

<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

 

3.添加Ehcache配置文件:ehcache.xml

 

十、Mybatis分页插件PageHelper

内置属性只关注查询数据SQL,不关注分页SQL,自动封装数据,pageHelper中国人

配置步骤:

1导入依赖

  com.github.pageHelper

<dependency>

<groupId>com.github.pagehelper</groupId>

<artifactId>pagehelper</artifactId>

<version>4.1.0</version>

</dependency>

 

2、配置插件

mybatis大配置文件当中配置pagehelper插件

<!--mybaitspagehelper分页插件-->

<plugins>

<plugin interceptor="com.github.pagehelper.PageHelper"></plugin>

</plugins>

 

3创建Mapper方法,实现查询

//根据新闻分类,和新闻标题进行动态SQL查询

public List<News> getNewsByTitleAndTid(@Param("ntid") Integer ntid,@Param("ntitle") String ntitle) throws Exception;

 

4创建小配置文件,不写limit

<resultMap id="newsMap" type="News">

<!--关联对象-->

<association property="topic" javaType="Topic"></association>

</resultMap>

 

 

 

<select id="getNewsByTitleAndTid" resultMap="newsMap">

select * from news,topic where news.ntid=topic.tid

<if test="ntid!=0">

and ntid=#{ntid}

</if>

<if test="ntitle!=null and ntitle!=''">

and ntitle like concat('%',#{ntitle},'%')

</if>

</select>

 

5创建Service

public PageInfo<News> getNewsByTitleAndTid(Integer tid, String ntitle, Integer pageNum, Integer pageSize) throws Exception;

 

6创建ServiceImpl层,实现分页

public class INewsServiceImpl implements INewsService {

private INewsMapper iNewsMapper;

public SqlSession sqlSession;

public INewsServiceImpl(){

sqlSession = MybatisUtil.getSqlSession();

iNewsMapper = sqlSession.getMapper(INewsMapper.class);

 

}

 

 

@Override

public PageInfo<News> getNewsByTitleAndTid(Integer tid, String ntitle, Integer pageNum, Integer pageSize) throws Exception {

//pageHelper分页配置

//步骤一:告诉PageHelper要第几页的多少条数据

Page<News> page = PageHelper.startPage(pageNum, pageSize);

//步骤二:查询数据,注意:之分页紧跟PageHelper后面的一条SQL

List<News> newsList = iNewsMapper.getNewsByTitleAndTid(tid, ntitle);

return page.toPageInfo();

}

}

 

7测试

@Test

public void pageHelper() throws Exception {

 

INewsServiceImpl service = new INewsServiceImpl();

PageInfo<News> pageInfo = service.getNewsByTitleAndTid(0, "", 2, 3);

System.out.println("===============================================================================");

List<News> list = pageInfo.getList();

for (News news : list) {

System.out.println(news.toString());

}

 

 

MybatisUtil.closeSqlSession(service.sqlSession);

 

}

8、PageHelper排序

调用startPage,直接传入排序的列,默认为升序 可以改为倒叙:列名 desc

public static <E> Page<E> startPage(int pageNum, int pageSize, String orderBy) {

Page<E> page = startPage(pageNum, pageSize);

page.setOrderBy(orderBy);

return page;

}

 

@Override

public PageInfo<News> getNewsByTitleAndTid(Integer tid, String ntitle, Integer pageNum, Integer pageSize) throws Exception {

//pageHelper分页配置

//步骤一:告诉PageHelper要第几页的多少条数据

Page<News> page = PageHelper.startPage(pageNum, pageSize,"ncreateDate desc");

//步骤二:查询数据,注意:之分页紧跟PageHelper后面的一条SQL

List<News> newsList = iNewsMapper.getNewsByTitleAndTid(tid, ntitle);

return page.toPageInfo();

}

 

 

 

十一、注解开发

1 @SELECT的使用方式

Mapper接口中方法上使用该注解,里面写SQL

//使用Select注解进行模糊查询

@Select("select * from news,topic where news.ntid=topic.tid and ntitle like concat('%',#{ntitle},'%')")

public List<News> getNewsByTitle(@Param("ntitle") String ntitle) throws Exception;

 

2 关联查询

可以使用@ResultMap关联使用resultMapid  或者也可以指向@ResultsID ,但是@ReusltMap@Results不能同时出现在一个方法上

2.2.1 关联查询一的一方

//使用注解关联映射

@Results(id = "newsMapByMapper",value = {

//关联一的一方

@Result(property = "topic",column = "ntid",one = @One(select="com.wdksoft.mapper.INewsMapper.getTopic"))

})

@Select("select * from news where ntitle like concat('%',#{ntitle},'%')")

public List<News> getNewsByTitle(@Param("ntitle") String ntitle) throws Exception;

 

 

//查询一的一方的数据

@Select("select * from topic where tid=#{ntid}")

public Topic getTopic(Integer ntid) throws Exception;

 

 

 

2.2.2 关联查询多的一方

 

@Results(id = "topicResult",value = {

@Result(id=true,property = "tid",column = "tid"),

//关联多的一方

@Result(property = "newsList",column = "tid",many = @Many(select = "com.wdksoft.mapper.ITopicMapper.getNews"))

})

//查询新闻分类编号为4的新闻,包含新闻集合

@Select("select * from topic where tid=#{tid}")

public Topic getTopic(Integer tid) throws Exception;

@Select("select * from news where ntid=#{tid}")

public List<News> getNews(Integer tid) throws Exception;

 

3 添加数据

//添加数据,添加数据返回主键@Options

@Insert("insert into topic(tname) values(#{tname})")

@Options(useGeneratedKeys = true,keyProperty = "tid")

public int insertTopic(Topic topic) throws Exception;

 

4 修改数据

 //修改数据

@Update("update topic set tname=#{tname} where tid=#{tid}")

public int updateTopic(Topic topic) throws Exception;

5删除数据

//删除数据

@Delete("delete from topic where tid=#{tid}")

public int deleteTopic(Integer tid) throws Exception;

 

十二、MyBatis项目开发-超市账单管理系统

1.超市账单管理系统-登录功能

1.1 创建一个MavenWeb工程,将所需要的的页面素材添加到webapp

1.2 导入依赖,Mybatis依赖以及JavaEE-api依赖

1.3 搭建分层,创建实体,在User实体当中植入角色对象

1.4 创建Mybatis大配置文件

1.5 创建Mapper接口层,内置一个登录的方法

 //登录

public Smbms_User loginUser(@Param("userCode") String userCode, @Param("userPassword") String userPassword) throws Exception;

1.6 创建小配置文件ISmbmsUserMapper.xml文件

<resultMap id="userRoleMap" type="Smbms_User">

<association property="smbms_role" javaType="Smbms_Role"></association>

</resultMap>

 

<select id="loginUser" resultMap="userRoleMap">

select * from smbms_user where userCode=#{userCode} and userPassword=#{userPassword}

</select>

 

1.7 创建Service层接口,创建业务方法

//登录

public Smbms_User loginUser(String userCode,String userPassword) throws Exception;

 

1.8 创建Service层接口实现类,通过SqlSession调用Mapper接口对象

//植入Mapper层对象

private ISmbmsUserMapper iSmbmsUserMapper;

public ISmbmsUserServiceImpl(){

SqlSession sqlSession = MybatisUtil.getSqlSession();

iSmbmsUserMapper=sqlSession.getMapper(ISmbmsUserMapper.class);

}

 

@Override

public Smbms_User loginUser(String userCode, String userPassword) throws Exception {

return iSmbmsUserMapper.loginUser(userCode,userPassword);

}

 

1.9 Servlet处理用户请求,调用Service

@WebServlet("/ISmbmsUserServlet")

public class ISmbmsUserServlet extends HttpServlet {

//植入Service层对象

private ISmbmsUserService iSmbmsUserService=new ISmbmsUserServiceImpl();

@Override

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

doPost(req, resp);

}

 

@Override

protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

String action=req.getParameter("action");

if(action!=null){

//登录逻辑

if(action.equals("loginUser")){

//接收用户名和密码

String userCode=req.getParameter("userCode");

String userPassowrd=req.getParameter("userPassowrd");

try {

Smbms_User smbms_user = iSmbmsUserService.loginUser(userCode, userPassowrd);

if(smbms_user!=null){

//保存用户数据到Session

req.getSession().setAttribute("user",smbms_user);

//跳转页面

req.getRequestDispatcher("welcome.jsp").forward(req,resp);

}else{

req.getRequestDispatcher("login.jsp").forward(req,resp);

}

} catch (Exception e) {

e.printStackTrace();

}

 

}

}

}

}

 

 

2.超市账单管理系统-账单分页列表

2.0 导入PageHelperFastJSON依赖,以及配置PageHelper插件

<plugins>

<plugin interceptor="com.github.pagehelper.PageHelper"></plugin>

</plugins>

2.1 搭建分层,实体,Bill账单植入一的一方供应商对象

2.2 创建Mapper接口,创建一个查询方法

//查询账单列表数据

public List<Smbms_Bill> getBill(@Param("productName") String productName, @Param("providerId") Integer providerId, @Param("isPayment") Integer isPayment) throws Exception;

 

2.3 创建Mapper小配置文件

<resultMap id="billProMap" type="Smbms_Bill">

<association property="smbmsProvider" javaType="Smbms_Provider"></association>

</resultMap>

 

<select id="getBill" resultMap="billProMap">

select * from smbms_bill,smbms_provider where smbms_bill.providerId=smbms_provider.pid

<if test="productName!=null and productName!=''">

and productName like concat('%',#{productName},'%')

</if>

<if test="providerId!=0">

and providerId=#{providerId}

</if>

<if test="isPayment!=0">

and isPayment=#{isPayment}

</if>

</select>

2.4 创建Service业务逻辑接口

//查询账单列表数据

public PageInfo<Smbms_Bill> getBill( String productName,Integer providerId,Integer isPayment,Integer pageNum,Integer pageSize) throws Exception;

 

2.5 创建Serivce业务逻辑接口实现类

public class ISmbmsBillServiceImpl implements ISmbmsBillService {

//植入Mapper层对象

private ISmbmsBillMapper iSmbmsBillMapper;

public ISmbmsBillServiceImpl(){

SqlSession sqlSession = MybatisUtil.getSqlSession();

iSmbmsBillMapper=sqlSession.getMapper(ISmbmsBillMapper.class);

}

 

@Override

public PageInfo<Smbms_Bill> getBill(String productName, Integer providerId, Integer isPayment, Integer pageNum, Integer pageSize) throws Exception {

//开始分页

Page<Smbms_Bill> page = PageHelper.startPage(pageNum, pageSize);

//执行查询

List<Smbms_Bill> bill = iSmbmsBillMapper.getBill(productName, providerId, isPayment);

return page.toPageInfo();

}

}

2.6 Servlet处理页面请求

@Override

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

String action=req.getParameter("action");

if(action!=null){

if(action.equals("getBill")){

//获取条件

String productName=req.getParameter("productName");

String providerId=req.getParameter("providerId");

String isPayment=req.getParameter("isPayment");

String pageNum=req.getParameter("pageNum");

String pageSize=req.getParameter("pageSize");

try {

//查询数据

PageInfo<Smbms_Bill> pageInfo = iSmbmsBillService.getBill(productName, 0, 0, Integer.parseInt(pageNum), Integer.parseInt(pageSize));

String pageInfoStr = JSON.toJSONString(pageInfo);

resp.getWriter().write(pageInfoStr);

} catch (Exception e) {

e.printStackTrace();

}

}

}

}

2.7 billList.jsp页面发送Ajax请求

$(function () {

load(1);

});

function load(pageNum) {

$.ajax({

url:"ISmbmsBillServlet",

type:"POST",

data:{"action":"getBill","pageNum":pageNum,"pageSize":3},

dataType:"JSON",

success:function (pageInfo) {

alert(pageInfo);

}

})

}

 

posted @ 2020-02-03 19:11  F阿东  阅读(220)  评论(0)    收藏  举报