第三阶段(day01)mybatis

第三阶段课程安排:

课程内容

1

mybatis基础

2

mybatis高级

3

AM:初步认识代理模式,了解mybatis源码

PM:权限模块dao层实现

4

spring容器

5

spring切面

6

AM:spring类配置,切面

PM:定义事务管理器实现事务切面

7

springmvc基础

8

springmvc高级

9

ssm框架整合

10

自习:完成至少两个业务模块
自习:完成至少两个业务模块
自习:完成至少两个业务模块

12

redis缓存及使用redis重构代码

13

工具篇:maven项目管理工具

14

AM:工具篇:maven聚合工程
PM:工具篇:jjwt组件学习及使用

15

springboot基础

16

springboot高级

17

springboot高级

mybatisplus学习

18

工具篇:远程接口访问与定时任务,异步任务

19

工具篇:短信与邮件发送

20

工具篇:excel与word生成

21

工具篇:阿里云对象oss存储

22-30

项目篇:天翼电子经销存

1. Mybaits介绍

进入mybatis官网自己学习:

mybatis作用:(***)

是一个持久层的框架,是对jdbc的封装.提高代码开发效率.

是一个半自动orm框架.对象关系映射框架,把表与对象做一一映射,目的是以操作对象的方式来操作表,mybatis是半自动orm,因为mybatis需要开发人员自定义sql语句.

hibernate都是纯oop的orm框架.执行效率太低.

jdbc-->dbutils-->mybatis-->hibernate

2.50分钟入门mybatis

新建普通的java工程:

1.安装mybatis环境,mysql驱动包.

新建lib包,加入这两个jar包

2.准备数据库表,表对应的实体类

新建数据库

新建表

id先自增

创建表对应实体类

新建包

将创建时间和修改时间对应的数据类型改为String,对应的set,get修改。

3.创建表对应的xml映射文件(此文件可以放在dao包,可以放在resources目录下)

src目录下习惯只放java源代码。而xml文件不需要编译,故最好单独建立文件夹。

新建resources目录,存放资源文件。

在resources下新建mapper目录。idea下不支持创建xml文件,需要编辑一个文件模板。

从官网拷贝相关代码到⑤中即可。

<?xml version="1.0" encoding="UTF-8" ?>        <!--xml声明-->
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">   <!--模板文件声明,可规定当前xml文件可打哪些标签-->
<mapper namespace="">
 
</mapper>

mapper目录下新建xml文件

起名sysuser-mapper

<!--namespace理解成类名,不同的映射文件namespace不能重复-->
<mapper namespace="aa.bb">
    <!--
    Sysuser getById(Integer id){
        DateSource ds;
        String sql = "select * from sys_user where id = ?";
        Connection c = ds.getConnection();
        PrepareStatement ps = c.prepareStatement(sql);
        ps.setInt(1,"10")
        ResultSet rs = ps.executeQuery()
    }
    理解成daoImpl实现类中写的sql
    id对应方法名
    只需要写sql语句
    -->
    <select id="getById" parameterType="java.lang.Integer" resultType="com.javasm.entity.SysUser">
       select * from sys_user where id =#{zzzzz}
    </select>
</mapper>

4.创建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>
    
</configuration>

resources目录下创建conf文件,起名mybatis

注:xml里不支持&符号

<configuration>

    <!--配置数据源.
    支持多数据库环境,但目前该技术已淘汰。一二阶段的项目操作一个数据库的数据,实际中大型项目可能把不同业务的表放到不同
    库里。分到不同库能减少访问压力,比如司机和乘客放在不同的库里。-->
    <environments default="704aDev">
        <!--一个environment代表一个数据库的连接配置-->
        <environment id="704aDev">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/704a"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

    <!--引入映射文件-->
    <mappers>
        <!--/开始表示根路径-->
        <mapper resource="/mappers/sysuser-mapper.xml"></mapper>
    </mappers>

</configuration>

5.加载xml配置文件创建SqlSessionFactory

新建test测试源码目录

新建com.javasm.TestGetById

public class TestGetById {
    @Test
    public void test1_getUserById(){
        //1.加载xml配置文件,读取为输入流
        //类加载器,此对象作用是去根路径(src,resources都是根路径)加载文件
        ClassLoader classLoader = TestGetById.class.getClassLoader();
        InputStream in = classLoader.getResourceAsStream("mybatis.xml");  //获取文件输入流

        //2.从xml中构建SqlSessionFactory,把该对象理解为DateSources连接池,即SqlSessionFactory里存放对某库的连接
        //SqlSessionFactory build = new SqlSessionFactoryBuilder().build(in,"704aDev");
        //build的第二个参数即environment对应的id,不加该参数则为environments的默认id
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);

        //3.从SqlSessionFactory中获取SqlSession,将SqlSession理解成Connection
        //session是会话对象,两端建立连接
        SqlSession session = factory.openSession();

        //4.curd增删改查
        //相当于执行某个类下的某个方法
        //selectOne方法只会查出一条记录。多条记录时,不能用该方法。
        Object o = session.selectOne("aa.bb.getById", 1);//需要Integer类型的参数

        //5.释放资源
        session.close();
    }
}

用ClassLoader读取流,用户从服务器下载文件到本地(根据文件名找到该文件),常用该方法。

实际上,mybatis里有专门的工具类

InputStream in = Resources.getResourceAsStream("mybatis.xml");

底层就是用ClassLoader。

数据库表中增加一行记录

运行该代码,报错

如何看报错代码?

"C:\Program Files\Java\jdk-11.0.14\bin\java.exe" -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:50557,suspend=y,server=n -ea -Didea.test.cyclic.buffer.size=1048576 -javaagent:C:\Users\Administrator\AppData\Local\JetBrains\IntelliJIdea2020.1\captureAgent\debugger-agent.jar -Dfile.encoding=UTF-8 -classpath "D:\idea\IntelliJ IDEA 2020.1.1\lib\idea_rt.jar;D:\idea\IntelliJ IDEA 2020.1.1\plugins\junit\lib\junit5-rt.jar;D:\idea\IntelliJ IDEA 2020.1.1\plugins\junit\lib\junit-rt.jar;F:\workspace\three\0920mybatis\out\test\0920mybatis;F:\workspace\three\0920mybatis\out\production\0920mybatis;F:\workspace\three\0920mybatis\lib\mybatis-3.4.1.jar;F:\workspace\three\0920mybatis\lib\mysql-connector-java-5.1.40-bin.jar;C:\Users\Administrator\.m2\repository\junit\junit\4.12\junit-4.12.jar;C:\Users\Administrator\.m2\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar" com.intellij.rt.junit.JUnitStarter -ideVersion5 com.javasm.TestGetById,test1_getUserById
Connected to the target VM, address: '127.0.0.1:50557', transport: 'socket'
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by org.apache.ibatis.reflection.Reflector (file:/F:/workspace/three/0920mybatis/lib/mybatis-3.4.1.jar) to method java.lang.Class.checkPackageAccess(java.lang.SecurityManager,java.lang.ClassLoader,boolean)
WARNING: Please consider reporting this to the maintainers of org.apache.ibatis.reflection.Reflector
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
Disconnected from the target VM, address: '127.0.0.1:50557', transport: 'socket'

org.apache.ibatis.exceptions.PersistenceException: 
### Error building SqlSession.
### The error may exist in /mappers/sysuser-mapper.xml
### Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: java.io.IOException: Could not find resource /mappers/sysuser-mapper.xml

	at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
	at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:80)
	at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:64)
	at com.javasm.TestGetById.test1_getUserById(TestGetById.java:21)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
Caused by: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: java.io.IOException: Could not find resource /mappers/sysuser-mapper.xml
	at org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration(XMLConfigBuilder.java:120)
	at org.apache.ibatis.builder.xml.XMLConfigBuilder.parse(XMLConfigBuilder.java:98)
	at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:78)
	... 24 more
Caused by: java.io.IOException: Could not find resource /mappers/sysuser-mapper.xml
	at org.apache.ibatis.io.Resources.getResourceAsStream(Resources.java:114)
	at org.apache.ibatis.io.Resources.getResourceAsStream(Resources.java:100)
	at org.apache.ibatis.builder.xml.XMLConfigBuilder.mapperElement(XMLConfigBuilder.java:366)
	at org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration(XMLConfigBuilder.java:118)
	... 26 more


Process finished with exit code -1

要么看最上面

org.apache.ibatis.exceptions.PersistenceException: 
### Error building SqlSession.
### The error may exist in /mappers/sysuser-mapper.xml
### Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: java.io.IOException: Could not find resource /mappers/sysuser-mapper.xml

找到

Could not find resource /mappers/sysuser-mapper.xml

要么看下面,最后一个Cause by。

找不到映射文件,路径写错了。

在配置文件中将路径修改

<!--引入映射文件-->
    <mappers>
        <mapper resource="mappers/sysuser-mapper.xml"></mapper>
    </mappers>

开头不需要加/

再次打断点运行

发现数据库里有下划线的字段,虽然在数据库有数据,但在idea没有数据。

6.从SqlSessionFactory中获取SqlSession

见5

7.执行curd操作

见5

3.核心对象(***)

SqlSessionFactoryBuilder,此对象一般称为构建器对象,是构建器模式的应用.

此对象new出来仅仅执行一次build方法,加载xml配置文件输入流,创建出SqlSessionFactory后,即可销毁. 
构建器模式:是GOF设计模式中的一种,作用来用来创建其他的单例类型的对象
          XXXXBuilder{
             YYYYbuild(){
                 
             }
          }

SqlSessionFactory,把该对象理解成DateSource连接池

此对象持有Configuration对象,configuration中包含Environment对象,包含数据库连接池.。
此对象持有Configuration对象,configuration中MappedStatement对象的集合,以namespace.id作为key,以MappedStatement来封装select标签的所有数据作为value.。
此对象生命周期:全局唯一 
此对象常用方法:openSession

SqlSession:此对象类比成Connection连接对象

此对象生命周期:每次进行数据库操作,都需要临时创建的对象,用完执行close进行销毁. 
此对象常用方法:selectOne,selectList,insert,delete,update,getMapper

23中GOF设计模式:单例模式,构建器模式.原型模式,工厂模式,访问者,观察者,适配器.代理...

4.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="704aDev">
        <!--一个environment代表一个数据库的连接配置-->
        <environment id="704aDev">

            <!--JDBC:启用事务控制
            或者MANAGED:没有回滚概念,每次操作直接到数据库-->
            <transactionManager type="JDBC"/>

            <!--POOLED:mybatis内部提供了PooledDataSource对象连接池
            UNPOOLED:mybatis不提供连接池
            JNDI:mybatis不提供连接池,也不临时打开Connection,由第三方的tomcat来管理数据库连接池,然后
            代码中通过命名目录服务jndi来获取第三方容器中的连接池。该技术已淘汰
            -->
            <dataSource type="POOLED">
    
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/704a"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

    <!--引入映射文件-->
    <mappers>
        <mapper resource="mappers/sysuser-mapper.xml"></mapper>
    </mappers>

</configuration>

配置文件其他常用标签(官网可查)

1.settings标签

<!--settings标签是mybatis的调整设置标签,会改变mybatis运行时的行为-->
<settings>
    <!--向控制台打印sql语句-->
    <setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

向右的箭头是输入的东西。

向左的箭头是返回的结果。

<settings>
    <setting name="logImpl" value="STDOUT_LOGGING"/>
    <!--开启数据库下划线命名自动映射到实体类的驼峰命名-->
    <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>

此时,数据库中有下划线的字段,对应数据就能传到实体类。

2.properties标签

点开dtd文件

properties标签的顺序在settings标签前,故应在settings标签前打properties标签,这样才会有提示。(顺序不对也会报错)

<!--用来加载XXX.properties配置文件-->
<properties resource="jdbc.properties"></properties>

在resources目录下新建jdbc.properties

(配置文件里不写这些数据,而另建立该文件是因为xml文件里不能打特殊符号)

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/704a
jdbc.username=root
jdbc.password=root

前面加jdbc是为了防止只写一个单词,而该单词是框架里的关键字,导致冲突。另一个原因,后续配置量会越来越大,这四个都是jdbc连接信息,归类便于配置。

对应的配置文件中配置数据源部分修改

<!--配置数据源。-->
<environments default="704aDev">
<environment id="704aDev">
    <transactionManager type="JDBC"/>
    <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>

3.typeAlias别名标签

<!--类型别名标签-->
<typeAliases>
    <!--为此类取一个别名-->
    <typeAlias type="com.javasm.entity.SysUser" alias="sysuser"></typeAlias>
</typeAliases>

对应映射文件中,resultType直接写类名的别名即可。

<mapper namespace="aa.bb">
    <!--parameterType可省略,刚开始用mybatis不建议省略,resultType不可省略-->
    <select id="getById" parameterType="java.lang.Integer" resultType="sysuser">
       select * from sys_user where id =#{zzzzz}
    </select>

    <select id="getByName" parameterType="java.lang.String" resultType="sysuser">
        select * from sys_user where uname like concat('%',#{sss})
    </select>

</mapper>

但不推荐该方式,因为一个项目的实体类很多,指定到上层包名即可

<!--类型别名标签-->
<typeAliases>
    <!--类名作为别名,不用包名,同时忽略大小写-->
    <package name="com.javasm"/>
</typeAliases>

此方式效果同上一个方式,但不需要每个类名都写别名。

忽略大小写,指resultType标签那里,sysuser可以是sYsuser等等。底层统一转小写。

但一定不要出现同名的类。

(mybatis里不支持通配的方式,mybatisPlus里支持,这里只是举例说明)

一般第三层包名是模块名 ,模块下的包名会保持一致。(即系统模块和订单模块都会有实体类entity)

如果两个模块的entity包下的类同名,则报错

此时配置文件如下:

<?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>
    <!--用来加载XXX.properties配置文件-->
    <properties resource="jdbc.properties"></properties>

    <!--调整运行时行为-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

    <!--类型别名标签-->
    <typeAliases>
        <package name="com.javasm"/>
    </typeAliases>

    <!--配置数据源。-->
    <environments default="704aDev">
        <environment id="704aDev">
            <transactionManager type="JDBC"/>
            <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>

    <!--引入映射文件-->
    <mappers>
        <mapper resource="mappers/sysuser-mapper.xml"></mapper>
    </mappers>

</configuration>

5.xml映射文件(***)

1.模糊查询

使用concat函数进行字符串拼接;也可以使用"%"进行拼接

(sql语句里都是单引号,像双引号这种不是正常用法)

<select id="getByName" parameterType="java.lang.String" resultType="com.javasm.entity.SysUser">
   select * from sys_user where uname like "%"#{ddd}
</select>
<select id="getByName" parameterType="java.lang.String" resultType="com.javasm.entity.SysUser">
        select * from sys_user where uname like concat('%',#{sss},'%')
</select>

从官网可查到参数类型对应的简化写法,叫内嵌别名

故,此时的映射文件为:

<?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属性,namespace理解成dao类名,不同的映射文件namespace不能重复-->
<mapper namespace="aa.bb">
    <!--parameterType可省略,刚开始用mybatis不建议省略,resultType不可省略-->
    <select id="getById" parameterType="int" resultType="sysuser">
       select * from sys_user where id =#{zzzzz}
    </select>

    <select id="getByName" parameterType="string" resultType="sysuser">
        select * from sys_user where uname like concat('%',#{sss})
    </select>
 
</mapper>

2.select

id:在同一个映射文件,不能重名.不可省略。

parameterType:可省略 。

resultType:不可省略。此属性值有以下情况:实体类名,简单类型(String,Date,基本类型),map。绝对不能出现List,set。

(简单类型是框架里的说法,可直接使用的类型都叫简单类型)

根据id查电话,没必要将结果封装到sysuser对象。

<select id="getUphoneById" parameterType="int" resultType="string">
    select uphone from sys_user where id =#{zzzzz}
</select>

resultType的值取决于要查的值是什么类型。

<select id="getMapDatasById" parameterType="int" resultType="map">
    select * from sys_user where id =#{zzzzz}
</select>

列名作为key,值作为value。

增加数据库记录

还是查含t的用户名的记录数,此时用selectOne方法不合适。

<select id="getByName" parameterType="string" resultType="sysuser">
    select * from sys_user where uname like concat('%',#{sss},'%')
</select>
public class TestMapperXml {
    @Test
    public void getByName() throws IOException {

        InputStream in = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        SqlSession session = factory.openSession();

        List<Object> t = session.selectList("aa.bb.getByName", "t");

        session.close();
    }
}

结果是用户集合,但resultType确是sysuser,resultType类比成返回值类型,只是类比。

resultType表示把单行记录封装的目标类型,故不能是List,set。

3.insert

<!--insert没有resultType属性-->
<insert id="save" parameterType="sysuser">
    insert into sys_user(uname,upwd,uphone,uwechat,uemail) values
    (#{uname},#{upwd},#{uphone},#{uwechat},#{sdept.dname})
</insert>
@Test
public void save() throws IOException {

    InputStream in = Resources.getResourceAsStream("mybatis.xml");
    SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
    SqlSession session = factory.openSession();

    SysUser u = new SysUser();
    u.setUname("XXXX");
    u.setUpwd("111");
    u.setUphone("1111");
    u.setUwechat("xxx333");

    //返回受影响行数
    int rows = session.insert("aa.bb.save", u);

    session.commit();

    session.close();
}

4.update

<!--update没有resultType属性-->
<update id="update" parameterType="sysuser">
     update sys_user set upwd=#{upwd},uphone=#{uphone} where id=#{id}
</update>
@Test
public void update1() throws IOException {

    InputStream in = Resources.getResourceAsStream("mybatis.xml");
    SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
    SqlSession session = factory.openSession();

    SysUser u = new SysUser();
    u.setId(1);
    u.setUpwd("111");
    u.setUphone("1111");

    //返回受影响行数
    int rows = session.update("aa.bb.update", u);

    session.commit();
    session.close();
}

<update id="update2" parameterType="map">
     update sys_user set upwd=#{a},uphone=#{b} where id=#{c}
</update>
@Test
public void update2() throws IOException {

    InputStream in = Resources.getResourceAsStream("mybatis.xml");
    SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
    SqlSession session = factory.openSession();

    Map<String,Object> map = new HashMap<>();
    map.put("a","ddd");
    map.put("b","xxx");
    map.put("c",1);

    //返回受影响行数
    int rows = session.update("aa.bb.update2", map);

    session.commit();
    session.close();
}

5.delete

<delete id="delByID" parameterType="int">
     delete from sys_user where id=#{id}
</delete>
@Test
public void delete() throws IOException {

    InputStream in = Resources.getResourceAsStream("mybatis.xml");
    SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
    SqlSession session = factory.openSession();

    int rows = session.delete("aa.bb.delByID", 8);

    session.commit();
    session.close();
}

6.#{}

#{}表示mybatis使用PrepareStatement预编译对象进行sql编译,传入动态参数.

大括号中出现值有以下情况:随意,实体类的成员变量名,map的key值.

1.如果传入的参数是简单类型,则随便写. 2.如果传入的参数是实体对象,则写成员变量名. 3.如果传入的参数是Map,则写map的key值.

参考insert标签,传入的参数是实体对象,则写成员变量名。

参考update标签,传入的参数是Map,则写map的key值。

也可以是嵌套模式(前后端交互很常见)

entity下新建SysDept

public class SysDept {
    private Integer id;
    private String dname;
//set get    
}

在SysUser里加入该字段

private SysDept sdept;
//set get

若前端传入的用户数据包含部门名称数据,将该名称填入邮箱字段:

可在SysDept加入部门名称的有参构造。(加了有参构造就加无参构造,防止覆盖出错)

<insert id="save" parameterType="sysuser">
    insert into sys_user(uname,upwd,uphone,uwechat,uemail) values
    (#{uname},#{upwd},#{uphone},#{uwechat},#{sdept.dname})
</insert>
@Test
    public void save() throws IOException {

        InputStream in = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        SqlSession session = factory.openSession();

        SysUser u = new SysUser();
        u.setUname("XXXX");
        u.setUpwd("111");
        u.setUphone("1111");
        u.setUwechat("xxx333");
        u.setSdept(new SysDept("财务部"));

        //返回受影响行数
        int rows = session.insert("aa.bb.save", u);

        session.commit();

        session.close();
    }

7.大于小于

大于 大于等于符号可以出现在sql语句

小于不行,因为<和标签的尖括号冲突。&lt;是xml标签里特有的符号(html里也这样写,是类xml语言)

<select id="getUsers" parameterType="int" resultType="sysuser">
     select * from sys_user where id &lt;= #{id}
</select>
@Test
public void getUser() throws IOException {

    InputStream in = Resources.getResourceAsStream("mybatis.xml");
    SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
    SqlSession session = factory.openSession();

    List<Object> objects = session.selectList("aa.bb.getUsers", 7);

    session.commit();
    session.close();
}

6.getMapper方法(***.难点)

难是底层理解难。用起来简单。

1.添加dao接口

2.在映射文件的namespace值:namespace必须是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">

<mapper namespace="com.javasm.sys.dao.SysUserDao">
<!--    SysUser getById(Integer id);-->
    <select id="getById" parameterType="integer" resultType="sysuser">
        select * from sys_user where id=#{id}
    </select>

<!--    List<SysUser> getUsers();-->
    <select id="getUsers" resultType="sysuser">
        select * from sys_user
    </select>

<!--    int save(SysUser u);-->
    <insert id="save">
        insert into sys_user (uname,uphone,upwd) values(#{uname},#{uphone},#{upwd})
    </insert>

<!--    int update(SysUser U);-->
    <update id="update">
        update sys_user set uname=#{uname},upwd=#{upwd} where id=#{id}
    </update>

<!--    int del(Integer id);-->
    <delete id="del">
        delete  from sys_user where id=#{id}
    </delete>


</mapper>

将映射文件引入到配置文件

<mappers>
    <mapper resource="mappers/sysuser-mapper.xml"></mapper>
    <mapper resource="mappers/sysuser-mapper2.xml"></mapper>
</mappers>

新建测试类TestGetMapper

public class TestGetMapper {
    @Test
    public void TestGetMapper() throws IOException {
        InputStream in = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        SqlSession session = factory.openSession();

        //没有实现类,却得到了Dao接口的对象。有了该对象就能调用它的方法
        SysUserDao ud = session.getMapper(SysUserDao.class);
        SysUser sysUser = ud.getById(1);
        List<SysUser> users = ud.getUsers();

        session.close();
    }
}

3.映射文件的select|insert|update|delte标签的id必须是dao接口的方法名.

见2

7.多参数传递(***)

1.把多个参数封装到实体对象

见inseret,update

2.把多个参数封装到map对象

见update

3.在dao接口的方法中定义多个形参

根据用户名,密码查询

在dao接口增加

SysUser getByUnameAndId(String uname,Integer id);
//mybatis底层操作永远只支持一个参数传递。传入多个参数,底层会把多个参数封装成Map
//key为0,1,表示第一个参数,第二个参数或者param1,param2

在映射文件

<!--parameter写的话,类型是map-->
<select id="getByUnameAndId" parameterType="map" resultType="sysuser">
    select * from sys_user where id=#{1} and uname=#{0}
</select>

或者

<!--parameter写的话,类型是map-->
<select id="getByUnameAndId" parameterType="map" resultType="sysuser">
    select * from sys_user where id=#{param2} and uname=#{param1}
</select>

在测试类

@Test
public void getByUnameAndPwd() throws IOException {
    InputStream in = Resources.getResourceAsStream("mybatis.xml");
    SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
    SqlSession session = factory.openSession();

    SysUserDao ud = session.getMapper(SysUserDao.class);
    SysUser s = ud.getByUnameAndId("fyt", 4);

    session.close();
}

或者

通过注解自己生成key

dao接口

SysUser getByUnameAndId(@Param("un") String uname, @Param("ui") Integer id);

映射文件

<select id="getByUnameAndId" resultType="sysuser">
    select * from sys_user where id=#{ui} and uname=#{un}
</select>

8.常见异常

java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for aa.bb.getById 
执行session对象的方法时,传入的namespace.id不存在。 (可能写错,可能未引入映射文件)   

ClassCastException: class java.lang.String cannot be cast to class java.lang.Integer
传入的参数类型与映射文件中parameterType的类型不一致

IllegalArgumentException: Mapped Statements collection already contains value for aa.bb.getById 
namespace.id重复    

ExecutorException: A query was run and no Result Maps were found for the Mapped Statement 'aa.bb.getById'.  It's likely that neither a Result Type nor a Result Map was specified.
select标签没有resultType或者resultMap属性进行结果映射.  

ReflectionException: There is no getter for property named 'a' in 'class com.javasm.sys.entity.SysUser'
 #{}括号中值写错

BindingException: Invalid bound statement (not found): com.javasm.sys.dao.SysuserDao.getByName
dao接口中的方法在映射文件中没有对应的标签id

9.注意事项

1.idea不允许创建project,再创N个Module.maven聚合工程中才这样使用.

2..iml与.idea隐藏了,不上传svn;

一个.iml文件就是一个modules。

3.设置idea的encoding编码:UTF-8.防止乱码

4.数据库字段的date(年月日),datetime(年月日时分秒),timestamp

实体类变量类型对应使用Date或者String。原生jdbc中,用Date合适,在orm框架中,用String合适,因为Date序列化json字符串需要指定日期格式.

5.free mybatis plugin

mybatisX,自动让dao接口和映射文件对应。

10总结:

配置文件只需要知道settings标签,日志,驼峰映射.

映射文件中全部.(#{}与传入的参数.select的返回值)

dao接口

getMapper方法

三个核心对象

#{}写法

参数写法

select 标签的返回值

11.事务相关知识补充

1、事务

事务是指作为一个逻辑工作单元执行的一系列操作,这些操作要么全部成功要么全部失败。事务确保了多个数据的修改作为一个单元来处理。

假如,张三在ATM机上给李四转账100元,在银行的业务系统中,主要会执行两步数据变更操作:

  1. 从张三的账户减去100元
  2. 给李四的账户增加100元

(简单的说,就是一个完整的事件集合)

2、提交事务

Commit Transaction,成功的结束,将所有的DML语句操作历史记录和底层硬盘数据来一次同步(增删改,查询不需要)

conn.commit();

3、事务回滚

End Transaction,失败的结束,将所有的DML(insert、update、delete)语句操作历史记录全部清空。

所谓回滚事务,简单来说就是当一个事务的某一个操作发生问题时,整个事务可以回滚掉,就像没有做任何操作一样,换言之当发生错误或事务被取消,则回滚事务。

当开启事务之后,所有的操作都会被存储在事务日志中,而只有当我们进行提交事务的操作后,才会将我们更新的数据同步到数据表中。

conn.rollback()

4.事务控制:

默认情况下,MySQL是自动提交事务的,即每一条INSERT、UPDATE、DELETE的SQL语句提交后会立即执行COMMIT操作。一旦命令被提交,就无法对它进行回滚操作。在使用事务时,需要关闭这个默认值:

conn.setAutoCommit(false); (使用事务时,需要关闭这个默认值)

5.事务关闭

所有操作执行完,需要将连接归还连接池。

coon.close()

(执行该操作前应该conn.setAutoCommit(true);恢复默认的自动提交)

相关例子:

Java中开启事务操作数据库_weixin_33738578的博客-CSDN博客https://blog.csdn.net/weixin_33738578/article/details/92718999

为确保事务中的连接是同一个,可将connection设为全局变量(跨线程,跨类),但这会导致线程安全问题。

ThreadLocal,缩小共享范围,可使全局共享变量成为相互隔离的线程内部的共享变量。

这里保证一个线程共享一个连接。

ThreadLocal<Connection> connThreadLocal =new ThreadLocal<>();  //线程锁,只在当前线程可用的东西 
Connection connection = connThreadLocal.get();

与数据库的连接------connection怎么拿?

若jar包只有类似mysql-connector-java-5.1.20-bin.jar的情况:

Connection con=DriverManager.getConnection(url:"jdbc:mysql://localhost:3306/704a", user:"root", password:"root");

具体可参考:

java如何连接数据库(新手上路)_行孤、的博客-CSDN博客_java链接数据库https://blog.csdn.net/qq_43403759/article/details/111198131

Java怎么连接数据库-java教程-PHP中文网https://www.php.cn/java-article-418073.html

(这个没加回滚和关闭)

以上是原生的jdbc连接数据库方式。

可以优化-------再加个jdbc.properties的配置文件。

若再引入druid(数据库连接池),多了个druid-1.0.9.jar包后,使用时,先得获取连接池对象,再获取连接对象。

DataSource dataSource = DruidDataSourceFactory.createDataSource(prop); 
Connection connection = dataSource.getConnection();

使用druid数据库连接池查询数据库中的数据(java)_南风~古草的博客-CSDN博客_数据库连接池查询https://blog.csdn.net/zhan_qian/article/details/123354032

写的再详细点,或者说若使用DruidDataSource这个对象时,那就先初始化它,一般都是:

public DruidDataSource druidDataSource(){
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setUrl(url);
        druidDataSource.setDriverClassName(driver);
        druidDataSource.setUsername(username);
        druidDataSource.setPassword(password);
        druidDataSource.setInitialSize(initialSize);
        return druidDataSource;
    }

然后:

Connection con= druidDataSource.getConnection();  

(一个是DataSource,一个是DruidDataSource,这两用法不一样!)

到了框架这一部分,用mybaties的配置文集引入jdbc.properties的配置文件,核心操作都是一样的。
​​​​​​​

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值