框架学习笔记

说明

本文为学习框架的过程笔记,更新中…

Maven配置环境变量及阿里云镜像加速

  1. 下载ApacheMaven;
    链接: link.
  2. 准备文件夹存放maven和repository(存放下载的jar包);
  3. 配置环境变量,将maven的bin目录设置到path中;
    1
  4. cmd使用mvn -v命令检测环境是否搭建完成;
  5. 对maven下conf文件夹中的setting进行如下设置。
    2
  <mirror>
    <id>aliyunmaven</id>
    <mirrorOf>*</mirrorOf>
    <name>阿里云公共仓库</name>
    <url>https://maven.aliyun.com/repository/public</url>
	</mirror>
  </mirrors>

概述

什么是框架?
框架是为解决开发过程中的一类问题而提出的一套解决方案,不同框架解决不同问题。
使用框架的好处:

  1. 框架封装了实现细节,让开发者不必了解过程以一种极简的方式实现功能。
  2. 大大提高了开发效率

三层架构:
表现层:展示数据
业务层:处理业务需求
持久层:完成数据库交互
1

持久层技术解决方案
JDBC技术:Connection、PreparedStatement、ResultSet。

Spring的JdbcTemplate:Spring中对JDBC的简单封装。

Apache的DBUtils:和Spring的JdbcTemplate很像,也是对JDBC的简单封装

补充:以上内容均不满足框架的优势,所以不是框架,JDBC是规范,Spring的JdbcTemplate和Apache的DBUtils是工具类。

Mybatis概述

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

总结:

  1. Mybatis是一个用Java写的持久层框架
  2. Mybatis封装了很多JDBC的操作细节,让开发者不必关心内容的实现过程,只需要关注sql语句本身。
  3. 它使用了ORM思想完成了结果集的封装;
    ORM(Object Relational Mapping)对象关系映射:将数据库表和实体类的属性对应起来,让开发者可以通过操作实体类来完成对数据库表的操作。

简单来说就是Mybatis框架为开发者省去了连接数据库的细节,而将重点放在sql语句的书写上。

Mybatis配置与使用

环境搭建

  1. 新建项目,勾选maven
    创建项目
  2. 配置pom.xml文件
    packaging
<dependencies>
        <dependency>
            <groupId>org.mybatis</groupId> 
            <artifactId>mybatis</artifactId>
            <version>3.5.5</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>  //数据库
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.19</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>  //日志
            <artifactId>log4j</artifactId>
            <version>1.2.12</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>  //单元测试
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
  1. 创建接口与类
//User.java

public class User implements Serializable {
    //成员变量 对应数据表
	//getter setter方法
	//重写toString
}

//IUserDao.java

public interface IUserDao {
	//抽象方法
    List<User> findAll();
    ...
}

  1. 配置Config的约束,创建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">
<!--Mybatis的主配置文件-->
<configuration>
<!--    配置环境-->
    <environments default="mysql"> <!--选择的默认值,名称无所谓-->
<!--        配置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:端口号/数据库名称"/>
                <property name="username" value="用户名"/>
                <property name="password" value="密码"/>
            </dataSource>
        </environment>
    </environments>

    <!--        指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件-->
    <mappers>
        <mapper resource="com/framework/dao/IUserDao.xml"/> //文件的地址,在resource文件下
    </mappers>
</configuration>
  1. 配置Mapper的约束,创建映射文件
<?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.framework.dao.IUserDao">
 	<!-- 查询语句 -->
    <select id="findAll" resultType="domain.User">  //与抽象方法名称一致
        select * from User;
    </select>
    
    <!-- parameterType的含义是参数的类型 -->
    <!--插入语句,标签是select也行,但是不能使用selectKey了-->
    <insert id="saveUser" parameterType="domain.User">
    	<!-- #{}如果是类中的getset方法是生成的直接写变量名字就行,否则要写get后面的名字 -->
        insert into user(username,address,sex,birthday)
        values(#{username},#{address},#{sex},#{birthday}); 
        
        <!-- 配置插入操作后,获取插入数据的id -->
        <!-- order表示获取id的操作是先于sql语句操作还是在sql之后后 -->
        <selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
            select last_insert_id();
        </selectKey>
    </insert>
    
	<!-- 更新操作 -->
	<select id="updateUser" parameterType="domain.User">
        update User set username = #{username},address = #{address},sex = #{sex},birthday = #{birthday} where id = #{id};
    </select>

	<!-- 删除操作 -->
	<!-- 这里的parameterType是整型,写法有integer和int的大小写以及java.lang.Integer -->
    <!-- 以及由于只有一个Integer参数,#{}可以写任意占位符 anything表示任意-->
    <delete id="deleteUser" parameterType="int">
        delete from User where id = #{anything};
    </delete>

	<!-- parameterType表示输入类型,resultType表示返回类型 -->
	<select id="findById" parameterType="Int" resultType="domain.User">
        select * from User where id = #{anything};
    </select>
    
	<!-- 根据QueryVo的条件查询 -->
    <!-- 需要更改的地方有parameterType以及#{}中的类型,格式为:对象名.属性。这个对象名在测试方法中定义-->
    <!-- 这是多个对象组成一个条件来实现查询 -->
    <select id="findByVo" parameterType="domain.QueryVoDemo" resultType="domain.User">
        select * from User where username like #{user.username};
    </select>

	<!--    使用if条件 where 1=1表示永真 如果加入了where标签,1=1可以省略-->
    <select id="findUserByCondition" parameterType="User" resultType="domain.User">
        select * from User <!--where 1=1-->
        <where>
            <if test="username != null">
                and username = #{username}
            </if>
            <if test="sex != null">
                and sex = #{sex};
            </if>
        </where>
    </select>
    
    <!-- select * from user where id in (1,2,3); -->
    <!-- ids在queryVo类中配置-->
    <select id="findUserInIds" parameterType="domain.QueryVoDemo" resultType="domain.User">
        select * from User
        <where>
            <if test="ids != null and ids.size()>0">
            <foreach collection="ids" open="and id in (" close=")" item="any" separator=",">
                #{any}
            </foreach>
            </if>
        </where>
    </select>
</mapper>

其中namespace和id是用于在多个语句的情况下,定位哪个具体的语句

补充:约束文件均创建在resource文件夹下。

  1. 抽取重复的sql语句
	<!-- 抽取重复的sql语句,可以节省逐条更改的时间 -->
    <!-- 重复的代码片段最好不加 ";" 避免出现拼接错误。如果只有一句sql,虽然语法不严谨但是可以使用  -->
    <sql id="defaultUser">
        select * from User
    </sql>

    <select id="findAll" resultType="domain.User">
        <include refid="defaultUser"></include>
    </select>
  1. 当实体类的属性名与数据库不同的时候。
	<!--  配置查询结果的列名和实体类的属性名的对应关系-->
    <resultMap id="userMap" type="UseR">
        <!-- 主键字段的对应关系,其中property是实体类的属性,column指实体类对应表中元组的名称,jdbcType是数据库中的类型,javaType是实体类的类型-->
        <id property="id" column="id"></id>
        <!-- 非主键字段的对应 -->
        <result property="username" column="username"></result>
        <result property="address" column="address"></result>
        <result property="sex" column="sex"></result>
        <result property="birthday" column="birthday"></result>
    </resultMap><!-- 此时配置完成后,要将resultType替换成resultMap -->
	<select id="findAll" resultMap="userMap">    
         select * from User;
    </select>

环境搭建的注意事项

  1. 关于名称,在Mybatis中持久层的操作接口名称和映射文件也叫做Mapper,所以IUserDao可以命名成IUserMapper。
  2. Idea中,创建包(package)时,"."具有分级的作用,而目录(directory)则不具备。1
  3. Mybatis的映射配置文件位置必须和dao接口的包结构相同。
    1
    2
  4. 映射配置文件的mapper标签namespace属性的值必须是dao接口的全限定类名。
  5. 映射配置文件的操作配置(如select),id属性的值必须是dao接口的方法名。
    说明:遵从3.4.5要求后即可不写dao的实现类。

完成测试

在test->java文件夹下,新建一个test类:

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接口的代理对象  这里用代理的方式不写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();
    }
}

使用注解

  1. 删除IUserDao.xml文件。2
  2. 在IUserDao接口文件中的方法上添加注解
    查询@Select("select * from users where username = #{username}")
    增添:@Insert("insert into users(username,password) values(#{username},#{password)")
    删除:@Delete("delete from role where id = #{id}")
    修改:@Update("update user set id=#{id},name=#{name} where id=#{id}")
  3. 修改Mybatis的主配置文件SqlMapConfig.xml
    修改

模糊查询

  1. 添加注解
    @Select("select * from user where username like '%${value}%'")
    模糊查询注解
  2. 添加模糊查询测试
   @Test
    public void selectLikeTest(){
//        List<User> users = userDao.selectLikeUser("%n%");
        List<User> users = userDao.selectLikeUser("n");//无通配符的模糊查询

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

注意

  1. 模糊查询注解{}内固定写value;
  2. 模糊查询{}外面不是#而是’ ’ (英文单引号) ,此外还要加上$;
  3. 不使用通配符的模糊查询(@Select("select * from user where username like '%${value}%'"))在查询中使用的是statement字符串拼接SQL(Preparing: select * from user where username like '%n%'),而另一种(@Select("select * from user where username like #{username}"))使用的是Preparestatement的参数占位符(Preparing: select * from user where username like ?),推荐使用第二种。

使用注解解决实体类中属性和表中名称不对应的解决办法

为需要注解的方法添加如下注解

@Results(id = "user", value = {
            @Result(id = true, column = "id", property = "userId"),
            @Result(column = "username", property = "userName"),
            @Result(column = "address", property = "userAddress"),
            @Result(column = "sex", property = "gender"),
            @Result(column = "birthday", property = "userBirthday"),
    })

说明

  1. id由于重复使用,value为替换对象。
public @interface Results {
    String id() default "";

    Result[] value() default {};
}
  1. 如果属性为id,则注解汇中设置id为true即可。
    Result
  2. column对应的是数据库字段名,property是实体类成员变量名。

重复使用
@ResultMap("user")3 使用resultmap来复用上面写过的注解,内容为注解id。

或者通过起别名的方式,这个执行效率最高

多表查询

使用注解

  1. 建立另一个查询
  2. 添加一对一映射
private User user;
    public User getUser() {
        return user;
    }
    public void setUser(User user) {
        this.user = user;
    }
  1. 添加注解
@Results(id = "account" , 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.framework.dao.IUserDao.selectUser"
                            ,fetchType = FetchType.EAGER))
    })
  1. 修改测试类
@Test
    public void findAll(){
        List<Account> accounts = accountDao.findAll();
        for (Account account : accounts) {
            System.out.println("-----每个账户的信息-----");
            System.out.println(account);
            System.out.println(account.getUser());
        }
    }

使用xml

<!-- 定义封装account和User的resultMap -->
    <resultMap id="accountUserMap" type="account">
        <id property="id" column="aid"></id><!-- 注意,在sql语句中 起了别名aid 则column应写成aid -->
        <result property="uid" column="uid"></result>
        <result property="money" column="money"></result>
        <!-- 一对一的关系映射:配置封装user的内容 column是外键 uid是外键链接的字段  -->
        <!--  property是副表的主表类对象,没起别名要写全限定类名
              column对应的是外键
              javaType用于提示封装到哪个对象  -->
        <association property="user" column="uid" javaType="user">
            <id property="id" column="id"></id>
            <result property="username" column="username"></result>
            <result property="address" column="address"></result>
            <result property="sex" column="sex"></result>
            <result property="birthday" column="birthday"></result>
        </association>
    </resultMap>

问题集合

  1. 诸如:Dependency ‘org.mybatis:mybatis:x.x.x’ not found
    not found
    可能问题:maven配置未完成。
    解决
    在这里插入图片描述

  2. Caused by: org.apache.ibatis.executor.ExecutorException:A query was run and no Result Maps were found for the Mapped Statement ‘com.framework.dao.IUserDao.findAll’. It’s likely that neither a Result Type nor a Result Map was specified.
    问题:Mapper中未设置返回值类型。
    解决1

  3. Cause: java.sql.SQLException: Unknown initial character set index ‘255’ received from server. Initial client character set can be forced via the ‘characterEncoding’ property.
    问题:字符集设置出错。
    解决:加上?useUnicode=true&amp;characterEncoding=utf8
    在这里插入图片描述

  4. Caused by:com.mysql.cj.exceptions.InvalidConnectionAttributeException: The server time zone value ‘?й???’ is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the ‘serverTimezone’ configuration property) to use a more specifc time zone value if you want to utilize time zone support.
    问题:时区问题。
    解决
    选择低版本的sql依赖
    或者
    在 JDBC 的连接 url 部分加上 serverTimezone=UTC(UTC可替换为Asia/Shanghai或者Asia/Hongkong)
    url: jdbc:mysql://localhost:3306/mydb01?serverTimezone=UTC 4

  5. Loading class com.mysql.jdbc.Driver'. This is deprecated. The new driver class iscom.mysql.cj.jdbc.Driver’. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
    问题:高版本Mysql驱动类使用不同的Drive语句。
    解决:将数据配置文件里com.mysql.jdbc.Driver修改为 com.mysql.cj.jdbc.Driver

  6. org.apache.ibatis.binding.BindingException: Type interface com.framework.dao.xxx is not known to the MapperRegistry.
    问题:找不到映射注册。
    解决:在< mapper >中添加xxx的全限定类名。
    或者
    将原来的< mapper class="…" > 改为 < package name = “包路径” >

  7. WARN Please initialize the log4j system properly.
    问题:未加载log4j包。
    解决:在Resources目录下添加该包。(可能需要重启IDEA)

  8. Expected one result (or null) to be returned by selectOne(), but found: x
    问题:selectOne()应返回一个结果(或null),但找到:x个。
    解决:使用集合接受返回数据。

  9. Cannot load connection class because of underlying exception: com.mysql.cj.exceptions.WrongArgumentException: Malformed database URL, failed to parse the connection string near ‘;characterEncoding=utf8&serverTimezone=Asia/Shanghai’.
    问题:无法识别 &amp;
    解决:使用注解的时候,字符串可以直接使用 &


  1. 不一样的版本可能会导致不一样的命名规则,也许有设置可以修改。 ↩︎

  2. 如果此文件的位置结构和接口包结构一样,则必须删除或移到其他文件目录下。 ↩︎

  3. 完全写法为@ResultMap(value = {"user"}),如果只有一个属性,且为value时,value可省;如果{}中的内容只有一个时,{}可省。 ↩︎

  4. 时区和字符设置可以用 &amp; 连接。 ↩︎

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值