JAVA学习笔记22——Maven,Mybatis

Maven

1. Maven简介

Maven 是一个项目管理工具,它包含了一个项目对象模型 (POM:Project Object Model),一组标准集合,一个项目生命周期(Project Lifecycle),一个依赖管理系统(Dependency Management System),和用来运行定义在生命周期阶段(phase)中插件(plugin)目标(goal)的逻辑。

2. 优势

1. 依赖管理
依赖是指: 一个java项目可能需要使用到第三方的jar包才能运行,那么我们说这个java项目依赖于第三方jar包。比如:SSM(spring,spring mvc mybatis),S2SH(Struts2 Spring hibernate)。
maven 工程中不直接将 jar 包导入到工程中,而是通过在 pom.xml 文件中添加所需 jar包的坐标,这样就很好的避免了 jar 直接引入进来,在需要用到 jar 包的时候,只要查找 pom.xml 文件,再通过 pom.xml 文件中的坐标,到一个专门用于”存放 jar 包的仓库”(maven 仓库)中根据坐标从而找到这些 jar 包,再把这些 jar 包拿去运行。
2.一键构建
我们的项目,往往都要经历编译、测试、运行、打包、安装 ,部署等一系列过程。
什么是构建?
指的是项目从编译、测试、运行、打包、安装 ,部署整个过程都交给 maven 进行管理,这个过程称为构建。
一键构建
指的是整个构建过程,使用 maven 一个命令可以轻松完成整个工作。

3. 概念模型

项目对象模型(POM):项目自身信息、项目运行所依赖的jar包信息、项目运行环境信息(jdk,tomcat信息)
依赖管理模型(Dependency):公司组织名称、项目名、版本号
在这里插入图片描述
默认生命周期:compile,test,package,install,deploy
每一个构建项目的命令对应了maven底层一个插件

Mybatis

1. 概述

Mybatis是一个优秀的基于Java的持久层框架,它内部封装了JDBC,使开发者只需要关注sql语句,而不用花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程
Mybatis通过xml或注解的方式将各种要执行的statement配置起来,并通过Java对象和statement中sql的动态参数进行映射生成最终执行的sql语句,最后由Mybatis框架执行sql并将结果映射为Java对象并返回
采用 ORM(Object Relational Mapping对象关系映射)思想解决了实体和数据库映射的问题,对 jdbc 进行了封装,屏蔽了 jdbc api 底层访问细节,使我们不用与 jdbc api 打交道,就可以完成对数据库的持久化操作。实体类中的属性和数据库表的字段名称保持一致。

1.1 框架

框架是软件开发中一套解决方案,不同的框架解决的是不同的问题
优点:
框架封装了很多细节,使开发者可以使用极简的方式实现功能,大大提高开发效率

1.2 三层架构

表现层:用于展示数据
业务层:处理业务需求
持久层:与数据库交互
在这里插入图片描述

1.3 持久层技术

JDBC
Connection
PreparedStatement
ResultSet

2. Mybatis入门

2.1 环境搭建

1.创建Maven工程并导入坐标
2.创建实体类和dao接口
3.创建Mybatis的主配置文件SqlMapConfig.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>
    <!--配置环境-->
    <environments default="mysql">
        <environment id="mysql">
            <!--配置事务的类型-->
            <transactionManager type="JDBC"></transactionManager>
            <!--配置数据源(连接池)-->
            <dataSource type="POOLED">
                <!--配置数据库的四个基本信息-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatisdb"/>
                <property name="username" value="root"/>
                <property name="password" value="1234"/>
            </dataSource>
        </environment>
    </environments>
    <!--指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件-->
    <mappers>
        <mapper resource="com/itheima/dao/IUserDao.xml"/>
    </mappers>
</configuration>

4.创建映射配置文件IUserDao.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.itheima.dao.IUserDao">
    <!--配置查询所有-->
    <select id="findAll">
        select * from user
    </select>
</mapper>

注意事项
1.在创建IUserDao.xml和IUserDao.java时名称是为了和我们之前的知识保持一致,在Mybatis中它把持久层的操作接口名称和映射文件也叫做Mapper
所以IUserDao和IUserMapper是一样的
2.在IDEA中创建目录时,它与包不一样
包在创建时:com.itheima.dao是三级结构
目录在创建时:com.itheima.dao是一级目录
3.mybatis的映射配置文件位置必须和dao接口的包结构相同
4.映射配置文件mapper标签namespace必须是dao接口的全限定类名
5.映射配置文件的操作配置,id属性的取值必须是dao接口的方法名
遵从了3,4,5后,我们在开发中就无须再写dao实现类

2.2 入门案例

第一步:读取配置文件
第二步:创建SqlSessionFactory工厂
第三步:创建SqlSession
第四步:创建Dao接口代理对象
第五步:执行dao中的方法
第六步:释放资源

public class MybatisTest {
    
    
    public static void main(String[] args) throws Exception {
    
    
        //1.读取配置文件
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.创建SqlSessionFactory工厂
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(in);
        //3.使用工厂生产SqlSession对象
        
        SqlSession session = factory.openSession();
        //4.使用SqlSession创建Dao接口的代理对象
        IUserDao userDao = session.getMapper(IUserDao.class);
        //5.使用代理对象执行方法
        List<User> users = userDao.findAll();
        for (User user : users) {
    
    
            System.out.println(user);
        }
        //6.释放资源
        session.close();
        in.close();
    }
}
<mapper namespace="com.itheima.dao.IUserDao">
    <!--配置查询所有-->
    <select id="findAll" resultType="com.itheima.domain.User">
        select * from user
    </select>
</mapper>

2.3 基于XML

步骤

  1. 编写接口
//根据ID查询用户
User getUserById(int id);
  1. 编写对应的mapper中的sql
<select id="getUserById" parameterType="int" resultType="com.itheima.domain.User">
        select * from user where id = #{id}
</select>
  1. 测试
    @Test
    public void getUserById() {
    
    
        SqlSession sqlSession = MybatisUtils.getSqlSession();

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

        User user = mapper.getUserById(1);
        System.out.println(user);

        sqlSession.close();
    }

Insert

<!--对象中的属性,可以直接取出来-->
<insert id="addUser" parameterType="com.kuang.pojo.User">
    insert into mybatis.user (id, name, pwd) values (#{id},#{name},#{pwd});
</insert>

update

    <update id="updateUser" parameterType="com.kuang.pojo.User">
        update mybatis.user set name=#{name},pwd=#{pwd}  where id = #{id} ;
    </update>

Delete

    <delete id="deleteUser" parameterType="int">
        delete from mybatis.user where id = #{id};
    </delete>

模糊查询

  1. Java代码执行的时候,传递通配符 % %
List<User> userList = mapper.getUserLike("%李%");
  1. 在sql拼接中使用通配符(可以防止sql注入)
select * from mybatis.user where name like "%"#{value}"%"

2.4.1 配置解析

属性
我们可以通过properties属性来实现引用配置文件
这些属性都是可外部配置且可动态替换的,既可以在典型的 Java 属性文件中配置,亦可通过 properties 元素的子元素来传递。

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

类型别名
类型别名是为 Java 类型设置一个短的名字。‘
存在的意义仅在于用来减少类完全限定名的冗余。

    <!--可以给实体类起别名-->
    <typeAliases>
        <typeAlias type="com.itheima.domain" alias="User"/>
    </typeAliases>

也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:
扫描实体类的包,它的默认别名就为这个类的 类名,首字母小写!

    <typeAliases>
        <package name="com.itheima.domain"/>
    </typeAliases>

在实体类比较少的时候,使用第一种方式。
如果实体类十分多,建议使用第二种。
第一种可以DIY别名,第二种则·不行·,如果非要改,需要在实体上增加注解

@Alias("user")
public class User {
    
    }
    <properties resource="jdbcConfig.properties"></properties>
    <typeAliases>
        <package name="com.itheima.domain"/>
    </typeAliases>
    <environments default="mysql">
        <environment id="mysql">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <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>

结果集映射

<!--结果集映射-->
<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" resultMap="UserMap">
    select * from mybatis.user where id = #{id}
</select>

2.4.2 分页查询

limit分页

  1. 接口
//分页
List<User> getUserByLimit(Map<String,Integer> map);
  1. Mapper.xml
<!--//分页-->
<select id="getUserByLimit" parameterType="map" resultMap="UserMap">
    select * from  mybatis.user limit #{startIndex},#{pageSize}
</select>
  1. 测试
@Test
public void getUserByLimit(){
    
    
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);

HashMap<String, Integer> map = new HashMap<String, Integer>();
    map.put("startIndex",1);
    map.put("pageSize",2);

    List<User> userList =  mapper.getUserByLimit(map);
    for (User user : userList) {
    
    
    System.out.println(user);
    }

    sqlSession.close();
    }

RowBounds分页

  1. 接口
List<User> getUserByRowBounds();
  1. mapper.xml
<select id="getUserByRowBounds" resultMap="UserMap">
    select * from  mybatis.user
</select>
  1. 测试
@Test
public void getUserByRowBounds(){
    
    
SqlSession sqlSession = MybatisUtils.getSqlSession();

//RowBounds实现
RowBounds rowBounds = new RowBounds(1, 2);

//通过Java代码层面实现分页
List<User> userList = sqlSession.selectList("com.kuang.dao.UserMapper.getUserByRowBounds",null,rowBounds);

    for (User user : userList) {
    
    
    System.out.println(user);
    }

    sqlSession.close();
    }

2.5 基于注解

把IUserDao.xml移除,在dao接口的方法上使用@Select注解,并且指定SQL语句。同时需要在SqlMapConfig.xml中的mapper配置时,使用class属性指定dao接口的全限定类名

public interface IUserDao {
    
    
    @Select("select * from user")
    List<User> findAll();
    @Insert("insert into user(username,address,sex,birthday)values(#{username},#{address},#{sex},#{birthday})")
    void saveUser(User user);
    @Update("update user set username=#{username},sex=#{sex},birthday=#{birthday},address=#{address} where id=#{id}")
    void updateUser(User user);
}
public class AnnotationCRUDTest {
    
    
    private InputStream in;
    private SqlSessionFactory factory;
    private SqlSession session;
    private IUserDao userDao;

    @Before
    public void init() throws IOException {
    
    
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        factory = new SqlSessionFactoryBuilder().build(in);
        session = factory.openSession();
        userDao = session.getMapper(IUserDao.class);
    }

    @After
    public void destroy() throws IOException {
    
    
        session.commit();
        session.close();
        in.close();
    }

    @Test
    public void testSave(){
    
    
        User user = new User();
        user.setUsername("mybatis");
        user.setAddress("北京");
        userDao.saveUser(user);
    }


    @Test
    public void testUpdate(){
    
    
        User user = new User();
        user.setId(49);
        user.setUsername("mybatis");
        user.setAddress("北京");
        user.setSex("男");
        user.setBirthday(new Date());
        userDao.updateUser(user);
    }

}
    <mappers>
        <package name="com.itheima.dao"/>
    </mappers>

实体类属性与数据库表中的对应关系:
假设属性名与列名不一一对应,使用Results注解

    @Select("select * from user")
    @Results(value = {
    
    
            @Result(id = true,column = "id",property = "userId"),
            @Result(column = "username",property = "userName"),
            @Result(column = "address",property = "userAddress"),
            @Result(column = "sex",property = "userSex"),
            @Result(column = "birthday",property = "userBirthday")
    })
    List<User> findAll();
public interface IUserDao {
    
    
    @Select("select * from user")
    @Results(id = "userMap",value = {
    
    
            @Result(id = true,column = "id",property = "userId"),
            @Result(column = "username",property = "userName"),
            @Result(column = "address",property = "userAddress"),
            @Result(column = "sex",property = "userSex"),
            @Result(column = "birthday",property = "userBirthday")
    })
    List<User> findAll();

    @Select("select * from user where id=#{id}")
    @ResultMap(value = {
    
    "userMap"})
    User findById(Integer userId);
}

2.6 一对一查询配置

    @Select("select * from account")
    @Results(id = "accountMap",value = {
    
    
            @Result(id = true,column = "id",property = "id"),
            @Result(column = "uid",property = "uid"),
            @Result(column = "money",property = "money"),
            @Result(property = "user",column = "uid",one = @One(select="com.itheima.dao.IUserDao.findById",fetchType= FetchType.EAGER))
    })
    List<Account> findAll();

2.7 多对一查询配置

按照查询嵌套处理

<!--
    思路:
        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 -->
    <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
</resultMap>

<select id="getTeacher" resultType="Teacher">
    select * from teacher where id = #{id}
</select>

按照结果嵌套处理

<!--按照结果嵌套处理-->
<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"/>
    </association>
</resultMap>

2.8 一对多查询配置

按照结果嵌套处理


    <!--按结果嵌套查询-->
    <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>

按照查询嵌套处理

<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="getStudentByTeacherId" column="id"/>
</resultMap>

<select id="getStudentByTeacherId" resultType="Student">
    select * from mybatis.student where tid = #{tid}
</select>

延迟加载:
就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载.

好处:
先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速
度要快。
坏处:
因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗
时间,所以可能造成用户等待时间变长,造成用户体验下降。

总结

  1. 关联 - association 【多对一】
  2. 集合 - collection 【一对多】
  3. javaType & ofType
    1. JavaType 用来指定实体类中属性的类型
    2. ofType 用来指定映射到List或者集合中的 pojo类型,泛型中的约束类型!

3. 缓存

3.1 基本概念

存在于内存中的临时数据
通过缓存策略来减少数据库的查询次数,从而提高性能。
适用于缓存:经常查询,不经常改变,数据的正确与否对最终结果影响不大

3.2 一级缓存

Mybatis中的SqlSession对象的缓存
当我们执行查询之后,查询的结果会同时存入到SqlSession为我们提供的一块区域中,该区域的结构是一个Map。当我们再查询同样的数据,Mybatis会先去Sqlsession中查询是否有,有的话直接拿出来用。
当SqlSession对象消失时,Mybatis的一级缓存也就消失了

分析
在这里插入图片描述
一级缓存是 SqlSession 范围的缓存,当调用 SqlSession 的修改,添加,删除,commit(),close()等方法时,就会清空一级缓存
第一次发起查询用户 id 为 1 的用户信息,先去找缓存中是否有 id 为 1 的用户信息,如果没有,从数据库查询用户信息。
得到用户信息,将用户信息存储到一级缓存中。
如果 sqlSession 去执行 commit 操作(执行插入、更新、删除),清空 SqlSession 中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
第二次发起查询用户 id 为 1 的用户信息,先去找缓存中是否有 id 为 1 的用户信息,缓存中有,直接从缓存中获取用户信息。

3.3 二级缓存

在这里插入图片描述
二级缓存指的是Mybatis中SqlSessionFactory对象的缓存,由同一个SqlSessionFactory对象创建的SqlSession共享缓存
使用步骤
第一步:让Mybatis框架支持二级缓存,在SqlMapConfig.xml中配置
第二步:让当前的映射文件支持二级缓存,在IUserDao.xml中配置
第三步:让当前的操作支持二级缓存,在Select标签中配置

猜你喜欢

转载自blog.csdn.net/qq_44708714/article/details/109744742
今日推荐