SSM学习笔记(全网最全,md文件在我的资源中,连接放在最后)

# Mybatis

## ORM思想:对象(Java对象)关系(关系型数据库)映射思想

## Mybatis 封装了JDBC

### 其他持久层技术的简介:

​    1、JDBC:

​        SQL夹杂在Java代码中耦合度高,导致硬编码内伤

​        维护不易且实际开发需求中SQL有变化,频繁修改的情况多见

​        代码冗长,开发效率低

​    2、Hibernate 和 JPA

​        操作相当简便,开发效率相当高

​        程序中的长难复杂SQL需要绕过框架

​        内部自动生产的SQL,不容易做特殊优化

​        基于全映射的全自动框架,大量字段的POJO进行部分映射时比较困难

​        反射操作太多,导致数据库性能下降

​    3、Mybatis

​        轻量级、性能出色

​        SQL和Java编码分开,功能边界清晰。Java代码专注业务,SQl语句专注数据

​        开发效率稍逊于Hibernate,但是完全能够接受

## 注意:

```java
    // int insertUser();
    //id和方法名保持一致
    <insert id="insertUser">
        INSERT INTO t_user(id,username,password,age,gender,email)
            VALUES(null,#{username},#{password},#{age},#{gender},#{email});
    </insert>
```

### 1、代理对象重写方法的过程:

**代理模式 **

创建代理对象的实现类  重写方法的过程为:根据接口名找到映射文件、根据方法名找到映射文件中的id、然后重写方法

其实就是框架为我们重写方法呗   跟我们重写一样

```java
    /*获取核心配置文件的输入流*/
    InputStream resource = Resources.getResourceAsStream("mybatis-config.xml");
    /*获取SqlSessionFactoryBuilder对象 用来创建工厂 */
    SqlSessionFactoryBuilder session = new SqlSessionFactoryBuilder();
    /* 用来获取工厂 */
    SqlSessionFactory factory = session.build(resource);
    /* sql会话对象 */
    /*SqlSession sqlSession = factory.openSession(true);   自动提交*/
       SqlSession sqlSession = factory.openSession();/*不会自动提交*/
    /* 获取代理对象  底层创建实现类  代理模式 */
       UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    mapper.insertUser();
    sqlSession.commit();
    sqlSession.close();
```

### 2、日志的级别(log4j中)

​    FATAL(致命)>ERROR(错误)>WARN(警告)>INFO(信息)>DEBUG(调试)
    从左到右打印的越来越详细
    如果 : 连WARN都要记录,那么比它等级更高的ERROR和FATAL也要记录

### 3、resultType与resultMap

```xml
    <!--
        resultType:设置结果类型,查询的数据转换为的Java类型
        resultMap:自定义映射,处理一对多或多对一的映射关系
    -->
    <select id="getUserById" resultType="com.ls.pojo.User">
        SELECT id, username, password, age, gender, email
        FROM t_user
        WHERE id = 1;
    </select>
```

mybatis框架的配置文件

```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>

    <!--mybatis核心配置文件中的标签必须按照指定的顺序配置
        (properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,
            objectWrapperFactory?,reflectorFactory?,plugins?,environments?,
            databaseIdProvider?,mappers?)
    -->

    <!--引入properties文件,此后可以在当前文件中使用${key}的方式访问value -->
    <properties resource="jdbc.properties"></properties>

    <!--
        typeAliases:设置类型别名,即为某个具体的类型设置别名
        在mybatis范围中,就可以使用别名表示具体的类型
    -->
    <typeAliases>
        <!--
            type:设置需要起别名的类型
            alias:设置某个类型的别名
            若不设置alias:当前类型拥有默认的别名,即类名不区分大小写
        -->
<!--        <typeAlias type="com.ls.pojo.User" alias="User"></typeAlias>-->
        <!--通过包来设置类型别名,指定包下所有的类  都有默认的别名,即类名不区分大小写  -->
        <package name="com.ls.pojo"/>
    </typeAliases>

    <!--default:设置默认使用的环境id-->
    <environments default="development">
        <!--
            environment:设置一个具体的链接数据库的环境
            属性:
                id:设置环境的唯一标识,不能重复
        -->
        <environment id="development">
            <!--
                transactionManager:设置事务管理器
                属性:
                type:设置事务管理方式
                type:"JDBC/MANAGED"
                JDBC:表示使用JDBC原生的事务管理方式      原生就是:可以设置手动提交  也可以设置自动提交  或者回滚 都是可以操控的
                MANAGED:被管理,例如Spring中的transaction
            -->
            <transactionManager type="JDBC"/>
            <!--
                dataSource:设置数据源
                属性:
                type:设置数据源的类型
                type:"POOLED/UNPOOLED/JNDI"
                POOLED:表示使用数据库连接池
                UNPOOLED:表示不使用数据库连接池  也就是说每次获取的链接都是重新创建的
                JNDI:表示使用上下文中的数据源
            -->
            <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>
    <!--引入mybatis的映射文件-->
    <mappers>
<!--        <mapper resource="com/ls/dao/UserMapper.xml"/>-->
        <!--
            以包的方式引入映射文件但是必须满足两个条件:
            1、mapper接口和映射文件所在的包必须一致
            2、mapper接口的名字和映射文件的名字必须一致
        -->
        <package name="com.ls.dao"/>
    </mappers>
</configuration>
```

### 4、MyBatis获取参数值的两种方式

MyBatis获取参数值的两种方式: ${}和#{}
${}的本质就是字符串拼接,#{}的本质就是占位符赋值I
${}使用字符串拼接的方式拼 接sql,若为字符串类型或日期类型的字段进行赋值时,需要手动加单引号;
但是#{}使用占位符赋值的方式拼接sq|,此时为字符串类型或日期类型的字段进行赋值时,可以自动添加单引号

### 5、MyBatis获取参数值的两种方式: #{}和${}

\#{}的本质是占位符赋值,${}的本质是字符串拼接

#### 1,若mapper 接口方法的参数为单个的字面量类型

此时可以通过#{}和\${}以任意的内容获取参数值,一-定要注意${} 的单引号问题

#### 2、若mapper接口方法的参数为多个的字面量类型

此时MyBatis会将参数放在map集合中,以两种方式存储数据
a> l以arg0, arg1...为键,以参数为值
b> l以param1, param2...为键,以参数为值
因此,只需要通过#{} 和\${}访问map集合的键,就可以获取相对应的值, - -定要注意${}的单 引号问题

```.xml
    <select id="checkLogin" resultType="user">
        SELECT *
        FROM t_user
        WHERE username = #{param1}
          and password = #{param2};
    </select>
```

#### 3、若mapper接口方法的参数为map集合类型的参数

只需要通过#{}和\${}访问map集合的键,就可以获取相对应的值, - -定要注意${}的单引号问题

```java
/*通过Map集合验证登录*/
 User checkLoginByMap(Map<String,Object> map);

<select id="checkLoginByMap" resultType="user">
    SELECT *
    FROM t_user
    WHERE username = #{username}
    and password = #{password};
</select>
```

#### 4、若mapper接口方法的参数为实体类类型的参数

只需要通过#{}和\${}访问实体类中的属性名,就可以获取相对应的属性值,- -定 要注意${}的单引号问题

#### 5、可以在mapper 接口方法的参数上设置@Param注解         常用

此时MyBatis会将这些参数放在map中,以两种方式进行存储
a>以@Param注解的value属性值为键,以参数为值
b>以param1 , param2 ......为键,以参数为值

因此,只需要通过#{} 和\${}访问map集合的键,就可以获取相对应的值, - -定要注意${}的单 引号问题

```java
    User checkLoginByParam(@Param("username") String username, @Param("password") String password);
```

## 常用的查询类型

### **Inetger**

```xml
<!-- Integer getCount();-->

<select id=" getcount" resultType="java.lang.Integer">
    select count(*) from t_ user
</select>
```

### **Map**

```xml
<!-- Map<String,Object> getUserByIdToMap(@Param("id") Integer id); -->
<!-- 查询的结果中 如果某个字段的值为null  是不会被放到map集合中的 -->
<select id="getUserByIdToMap" resultType="map">
    SELECT * FROM t_user WHERE id=#{id};
</select>
```

### **特殊的Map和List**

```java
    /*  查询所有的用户信息为map集合
            若查询的数据有多条时,并且要将每条数据转换为map集合
            此时有两种解决方案:
            1.将mapper接口方法的返回值设置为泛型是map的ist集合
            2、 可以将每条数据转换的map集合放在- 一个大的map中, 但是必须要通过@MapKey注解
                将查询的某个字段的值作为大的map的键
    */
    List<LinkedHashMap<String,Object>> getAllUserToListMap();    //LinkedHashMap只是为了排序

    @MapKey("id")
    Map<Integer,Object> getAllUserToMap();
```

### 模糊查询

```xml
<!--模糊查询-->
<select id="getUserByLike" resultType="com.ls.pojo.User">
    <!-- SELECT * FROM t_user where username like '%${mohu}%'; -->
    <!--字符串拼接-->
    <!-- SELECT * FROM t_user where username like concat('%',#{mohu},'%'); -->
    <!--最常用-->
    SELECT * FROM t_user where username like "%"#{mohu}"%";
</select>
```

### 批量删除

```xml
<!--批量删除-->
<delete id="deleteMoreUser">
    delete from t_user where id in (${ids});
</delete>
```

### 获取自增的主键

```xml
<!--void insertUser(User user);
    useGeneratedKeys使用自增的主键
    keyProperty 获取自增的主键并添加到user的id属性中
-->
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id" >
    INSERT INTO t_user(id, username, password, age, gender, email)
    values (null, #{username}, #{password}, #{age}, #{gender}, #{email});
</insert>
```

### 字段名和属性名不一致

修改配置文件

```xml
<!--将下划线命名映射为驼峰命名-->
<settings>
    <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
```

映射文件

```xml
<!--
    字段名和属性名不一-致的情况, 如何处理映射关系
        1.为查询的字段设置别名,和属性名保持一致
        2,当字段符合MySQL的要求使用_,而属性符合java的要求使用驼峰
            此时可以在yBatis的核心配置文件中设置一个全局配置, 可以自动将下划线映射为驼峰
            emp_id:empId  emp_name:empName
-->

<select id="getEmpByEmpId" resultType="com.ls.pojo.Emp">
    <!--select emp_id empId , emp_name empName , age , gender ,dept_id deptId from t_emp where emp_id = #{empId};-->
    select * from t_emp where emp_id = #{empId};
</select>
```

### 使用resultMap

```xml
<!--
    resultMap:设置自定义的映射关系
    id:唯一标识
    type:处理映射关系的实体类的类型
    常用的标签:
        id:处理主键和实体类中属性的映射关系
        result:处理普通字段和实体类中属性的映射关系
        column:设置映射关系中的字段名,必须是sql查询出的某个字段
        property:设置映射关系中属性的属性名,必须是处理的实体类类型中的属性名
        association:处理多对一的映射关系(处理实体类类型的属性)
        collectiqn:处理一对多的映射关系(处理集合类型的属性)
-->

<resultMap id="EmpMap" type="com.ls.pojo.Emp">
    <id column="emp_id" property="empId"></id>
    <result column="emp_name" property="empName"></result>
    <result column="age" property="age"></result>
    <result column="gender" property="gender"></result>
    <result column="dept_id" property="deptId"></result>
</resultMap>

<select id="getEmpByEmpId" resultMap="EmpMap">
    select * from t_emp where emp_id = #{empId};
</select>
```

###  多对一(对象) 必会

#### 处理方式一:

```xml
实体类:{
    @Data
    public class Emp {
        private Integer empId;
        private String empName;
        private Integer age;
        private char gender;
        private Dept dept;
    }
}

    <!-- 通过 级联的方式 -->
<resultMap id="EmpAndDept" type="com.ls.pojo.Emp">
        <id column="emp_id" property="empId"></id>
        <result column="emp_name" property="empName"></result>
        <result column="age" property="age"></result>
        <result column="gender" property="gender"></result>
        <result column="dept_id" property="dept.deptId"></result>
        <result column="dept_name" property="dept.deptName"></result>
    </resultMap>
    
    <select id="getEmpAndDeptByEmpId" resultMap="EmpAndDept">
        select t_emp.*, t_dept.*
        from t_emp
                 left join t_dept on t_emp.dept_id = t_dept.dept_id
        where emp_id = #{empId};
    </select>
```

#### **处理方式二(常用):**

```xml
实体类:{
    @Data
    public class Emp {
        private Integer empId;
        private String empName;
        private Integer age;
        private char gender;
        private Dept dept;
    }
}

    <!--
        association:处理多对一-的映射关系(处理实体类类型的属性)
        property:设置需要处理映射关系的属性的属性名
        javaType:设置要处理的属性的类型
    -->
    <resultMap id="EmpAndDept" type="com.ls.pojo.Emp">
        <id column="emp_id" property="empId"></id>
        <result column="emp_name" property="empName"></result>
        <result column="age" property="age"></result>
        <result column="gender" property="gender"></result>
        <association property="dept" javaType="com.ls.pojo.Dept">
            <id column="dept_id" property="deptId"></id>
            <result column="dept_name" property="deptName"></result>
        </association>
    </resultMap>
    
    <select id="getEmpAndDeptByEmpId" resultMap="EmpAndDept">
        select t_emp.*, t_dept.*
        from t_emp
                 left join t_dept on t_emp.dept_id = t_dept.dept_id
        where emp_id = #{empId};
    </select>
```

#### 处理方式三(分步查询):

分步查询的优点:可以实现延迟加载
    但是必须在核心配置文件中设置全局配置信息:
        lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载
        aggressiveLqzyLoading:当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载

​        此时就可以实现按需加载,获取的数据是什么,就只会执行相应的sql。 此时可通过association和 collection
            中的fetchType属性设置当前的分步查询是否使用延迟加载,fetchType="lazy(延迟加 载)| eager(立即加载)"

```xml
<association property="dept" fetchType="eager" <!--实现立即加载  也可以设置成lazy设置成懒加载--> 
             select="com.ls.mapper.DeptMapper.getDeptById"
             column="dept_id"></association>
```

```xml
一个Mapper.xml
<!--
    property:设置需要处理映射关系的属性的属性名
    select:设置分步查询的sql的唯一标识
    column:将查询出的某个字段作为分步查询的sqL的条件
-->
<resultMap id="EmpAndDeptStep" type="com.ls.pojo.Emp">
    <id column="emp_id" property="empId"></id>
    <result column="emp_name" property="empName"></result>
    <result column="age" property="age"></result>
    <result column="gender" property="gender"></result>
    <association property="dept"   select="com.ls.mapper.DeptMapper.getDeptById"
         column="dept_id"></association>
</resultMap>
<select id="getEmpAndDeptByStepOne" resultMap="EmpAndDeptStep">
    select * from t_emp where emp_id=#{empId};
</select>


另一个Mapper.xml
<select id="getDeptById" resultType="dept">
    select * from t_dept where dept_id=#{deptId};
</select>
```

### 一对多(集合)必会

#### 处理方式一:

```xml
    <!--
        处理一对多的映射关系:
            1、collection
            2、分步查询
    -->
    <resultMap id="DeptAndEmp" type="dept">
        <id column="dept_id" property="deptId"></id>
        <result column="dept_name" property="deptName"></result>
        <!--
            ofType:设置集合中存储的数据的类型
        -->
        <collection property="emps" ofType="emp" >
            <id column="emp_id" property="empId"></id>
            <result column="emp_name" property="empName"></result>
            <result column="age" property="age"></result>
            <result column="gender" property="gender"></result>
        </collection>
    </resultMap>

    <select id="getDeptAndEmpByDeptId" resultMap="DeptAndEmp">
        select t_emp.*, t_dept.*
        from t_dept
                 left Join t_emp on t_dept.dept_id = t_emp.dept_id
        where t_dept.dept_id = #{deptId};
    </select>
```

#### 处理方式二(分页查询):

```xml
    <!--
        处理- -对多的映射关系:
            1、collection
            2、分步查询
    -->
    <resultMap id="DeptAndEmp" type="dept">
        <id column="dept_id" property="deptId"></id>
        <result column="dept_name" property="deptName"></result>
        <collection property="emps" fetchType="lazy"
                select="com.ls.mapper.DeptMapper.getEmpById"
                column="dept_id"
        ></collection>
    </resultMap>
    
    <select id="getDeptAndEmpByDeptId" resultMap="DeptAndEmp">
        select * from t_dept where dept_id = #{deptId}
    </select>

    <select id="getEmpById" resultType="emp">
        select *
        from t_emp
        where dept_id = #{deptId};
    </select>    
```

## 动态SQL

### if标签和Where标签

```xml
<!--
    动态SQL :
    1. if,通过test属性中的表达式判断标签中的内容是否有效(是否会拼接到sql中)
    2、where
        a.若where标签中有条件成立,会自动生成where关键字
        b.会自动将where标签中内容前多余的and去掉,但是内容后多余的and无法去掉
        c.若where标签中没有任何一个条件成立,则where没有任何功能
-->
<select id="getEmpByCondition" resultType="com.ls.pojo.Emp">
    select * from t_emp
    <where>
        <if test="empName != null and empName != ''">
            emp_name = #{empName}
        </if>
        <if test="age != null and age != ''">
            and age = #{age}
        </if>
        <if test="gender != null and gender != ''">
            and gender = #{gender}
        </if>
    </where>
</select>
```

### trim标签

```xml
<!--
    trim
    prefix,suffix: 在标签中内容前面或后面添加指定内容
    prefixoverrides,suffixoverrides: 在标签中内容前面或后面去排指定内容
-->
<select id="getEmpByCondition" resultType="com.ls.pojo.Emp">
    select * from t_emp
    <trim prefix="where" prefixOverrides="and">
        <if test="empName != null and empName != ''">
            emp_name = #{empName}
        </if>
        <if test="age != null and age != ''">
            and age = #{age}
        </if>
        <if test="gender != null and gender != ''">
            and gender = #{gender}
        </if>
    </trim>
</select>
```

### choose、when、otherwise三个标签联合使用

```xml
<!--
    choose, when, otherwise
    相当于java中的if...else if...else
    when至少设置一一个,otherwise最多设置 1个
-->
<select id="getEmpByCondition" resultType="com.ls.pojo.Emp">
    select * from t_emp
    <where>
        <choose>
            <when test="empName != null and empName != ''">
                emp_name = #{empName}
            </when>
            <when test="age != null and age != ''">
                and age = #{age}
            </when>
            <when test="gender != null and gender != ''">
                and gender

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Java SSMSpring+SpringMVC+MyBatis)是一种基于Java语言的Web开发框架。学习这个框架的过程,我深刻体会到它的强大和灵活性。 首先,Spring框架为开发者提供了一个强大的IOC(Inversion of Control)容器,它能够管理和注入对象,减少了代码之间的耦合性。通过配置文件或注解,我们可以轻松地定义和获取各种对象,提高了代码的可维护性和可扩展性。 其次,SpringMVC框架是一种MVC(Model-View-Controller)设计模式的实现,它用于处理Web请求和响应。通过配置一个请求映射表和处理器,我们可以将请求分发给相应的控制器进行处理,并将处理结果返回给客户端。SpringMVC还提供了一些便捷的注解和标签,用于简化页面的渲染和参数的绑定。 最后,MyBatis是一种优秀的持久化框架,它能够将数据库操作与Java对象之间的映射简化为简单的配置。通过编写SQL映射文件和定义POJO(Plain Old Java Object)类,我们可以方便地进行数据库的增删改查操作,而无需编写冗长的SQL语句。 在学习Java SSM框架的过程,我深入理解了软件开发过程的MVC思想,并学会了如何利用SpringSpringMVC和MyBatis来实现一个完整的Web应用程序。通过不断的实践和调试,我逐渐培养了自己解决问题和调试代码的能力。 总结起来,学习Java SSM框架使我深入理解了软件开发的各个环节,并提升了我的编码能力和开发效率。我相信这些知识和经验将对我的职业发展和项目实施起到积极的促进作用。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值