吃个饭,回来再写了 QAQ
以上时间保存:2019-07-27 12:39
-------------------------------------
以下开始时间:2019-08-05 00:55
miss rainbow
-------------------------------------我是分界线----------------------------------------
1.什么是mapper代理接口方式?
MyBatis之mapper代理方式。mapper代理使用的是JDK的动态代理策略
2.使用mapper代理方式有什么好处
使用这种方式可以不用写接口的实现类,免除了复杂的方法,使得代码更加清晰易懂
按照以前的DAO 开发模式 ,我们有一个写了一个接口类 然后需要写这接口的实现类
现在就是MyBATis 通过帮我们生成了这个实现了。而我们要做的就是配置好这实现类的 XML。
也就是说 使用了mybatis 开发中不需要写数据库的实现类 而只要实现接口 所有的实现又mybatis的配置文件去生成。
个人dao开发模式案例传送门:https://www.cnblogs.com/ccoonngg/p/11306604.html
3.使用mappper代理方式要遵循什么规范?
1.接口名要和对应的映射文件的名称相同(只是后缀名不同)
2.mapper.xml中namespace等于mapper接口地址。(也就是全限定类名)
3.mapper.java 接口中的方法名和mapper.xml中statement的id一致。
4.mapper.java 接口中的方法输入类型和mapper.xml中statement的parameterType指定的类型一致。
5.mapper.java 接口中的方法返回值类型和mapper.xml中statement的resultType指定的类型一致。
-------------------------------------我是分界线----------------------------------------
前期mysql准备
create database cong use cong; create table account( id int primary key auto_increment, name varchar(40), money float )character set utf8 collate utf8_general_ci; insert into account(name,money) values('aaa',1000); insert into account(name,money) values('bbb',1000); insert into account(name,money) values('ccc',1000);
增删查改主要如下
<!--查询所有,如果返回多个结果,mybatis会自动把返回的结果放在list容器中 --> <select id="findAll" resultType="account"> select * from account </select> <select id="findById" parameterType="int" resultType="account"> select * from account where id = #{id} </select> <!-- 模糊查询 --> <select id="findByName" parameterType="String" resultType="account"> select * from account where name like #{name}; </select> <!-- 聚合函数,查询所有 --> <select id="findTotal" resultType="int"> select count(*) from account; </select> <!-- 保存 --> <insert id="saveAccount" parameterType="account"> insert into account(name,money)values(#{name},#{money}); </insert> <update id="updateAccount" parameterType="account"> update account set name=#{name},money = #{money} where id = #{id} </update> <delete id="deleteAccount" parameterType="int"> delete from account where id = #{id} </delete>
1.创建maven项目,导入相关约束
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.cong</groupId> <artifactId>mybatis_account_CRUD</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <dependencies> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.5</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies> </project>
2.创建com.cong.pojo.Account类
package com.cong.pojo; public class Account { private int id; private String name; private float money; @Override public String toString() { return "Account{" + "id=" + id + ", name='" + name + '\'' + ", money=" + money + '}'; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public float getMoney() { return money; } public void setMoney(float money) { this.money = money; } }
3.创建com.cong.mapper.AccountMapper接口
package com.cong.mapper; import com.cong.pojo.Account; import java.util.List; public interface AccountMapper { List<Account> findAll(); Account findById(int id); List<Account> findByName(String name); int findTotal(); void saveAccount(Account account); void updateAccount(Account account); void deleteAccount(int id); }
4.在resources下创建com\cong\mapper目录,创建AccountMapper.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"> <!-- namespace:命名空间,是AccountMapper.java接口的全类名 --> <mapper namespace="com.cong.mapper.AccountMapper"> <!-- id:statement的id 或者叫做sql的id parameterType:声明输入参数的类型 resultType:声明输出结果的类型,应该填写pojo的全路径 #{}:输入参数的占位符,相当于jdbc的? --> <!-- resultMap 标签可以建立查询的列名和实体类的属性名称不一致时建立对应关系。从而实现封装。 这样写了的话,返回结果用的是resultMap,而不是resultType id 属性:给定一个唯一标识,是给查询 select 标签引用用的 type 属性:指定实体类的全限定类名 id 标签:(resultMap标签里面的id)用于指定主键字段 result 标签:用于指定非主键字段 column 属性:用于指定数据库列名 property 属性:用于指定实体类属性名称 --> <resultMap id="account" type="com.cong.pojo.Account"> <!--不过在这个例子当中,我们的实体类与数据库的属性名称一致,写不写都行,只为演示--> <id column="id" property="id"></id> <result column="name" property="name"></result> <result column="money" property="money"></result> </resultMap> <!--查询所有,如果返回多个结果,mybatis会自动把返回的结果放在list容器中 --> <select id="findAll" resultMap="account"> select * from account </select> <select id="findById" parameterType="int" resultType="account"> select * from account where id = #{id} </select> <!-- 模糊查询 --> <select id="findByName" parameterType="String" resultType="account"> <!-- 有两种写法, 一种是like #{name},name是数据库中的属性,这样在测试的时候需要这样写:.selectList("%关键字%") 一种是like '%${value}%',这个value是固定写法,这样在测试的时候需要这样写:.selectList("关键字") 两种写法有着根本上的不同 --> <!--select * from account where name like '%${value}%';--> select * from account where name like #{name}; </select> <!-- 聚合函数,查询所有 --> <select id="findTotal" resultType="int"> select count(*) from account; </select> <!-- 保存,并且返回保存的对象在数据库中的id --> <insert id="saveAccount" parameterType="account"> <!-- selectKey 标签实现主键返回 keyColumn :主键对应数据库表中的哪一列 keyProperty :主键对应pojo中的哪一个属性 order :设置在执行insert语句之前执行查询id的sql,还是在执行insert语句之后执行查询id的sql LAST_INSERT_ID() 是mysql的函数,返回auto_increment自增列新记录id值 resultType:设置返回id的类型 --> <selectKey keyColumn="id" keyProperty="id" order="AFTER" resultType="int"> SELECT LAST_INSERT_ID() </selectKey> insert into account(name,money)values(#{name},#{money}); </insert> <update id="updateAccount" parameterType="account"> update account set name=#{name},money = #{money} where id = #{id} </update> <delete id="deleteAccount" parameterType="int"> delete from account where id = #{id} </delete> </mapper>
5.在resources目录下创建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> <typeAliases> <!-- typeAlias用于配置别名。type属性指定的是实体类全限定类名。 alias:指定别名,当指定了别名就再区分大小写 批量起别名的情况下使用,为某个类型指定新的别名(避免别名重复) package:为某个包下所有类批量起别名(常用) 用于指定要配置别名的包,当指定之后,该包下的实体类都会注册别名,并且类名就是别名,不再区分大小写 写了别名之后,在mapper文件中,返回值就不用写全限定类名了,直接写别名 --> <!--<typeAlias type="com.cong.pojo.Account" alias="account"></typeAlias>--> <package name="com.cong.pojo"></package> </typeAliases> <!--和spring整合之后,environments将被废除 --> <environments default="account"> <environment id="account"> <!-- 使用JDBC事物管理 --> <transactionManager type="JDBC"></transactionManager> <!-- 数据库连接池 --> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql://localhost:3306/cong"></property> <property name="username" value="root"></property> <property name="password" value="123456"></property> </dataSource> </environment> </environments> <!-- 告诉 MyBatis 到哪里去找到sql语句 可以使用相对于类路径的资源引用, 或完全限定资源定位符(包括 file:/// 的 URL),或类名和包名等 --> <mappers> <!-- 使用相对于类路径的资源引用 --> <mapper resource="com/cong/mapper/AccountMapper.xml"></mapper> <!-- 使用完全限定资源定位符(URL) --> <!--<mapper url="file:///D:/java/code/mybatis/mybatis_account_CRUD/src/main/resources/com/cong/mapper/AccountMapper.xml"></mapper>--> <!-- 下面两个需要AccountMapper.xml与AccountMapper.java有相同的目录结构 --> <!-- 使用映射器接口实现类的完全限定类名 --> <!--<mapper class="com.cong.mapper.AccountMapper"></mapper>--> <!-- 将包内的映射器接口实现全部注册为映射器 --> <!--<package name="com.cong.mapper"></package>--> </mappers> </configuration>
6.在resources目录下创建log4j.properties文件
# Set root category priority to INFO and its only appender to CONSOLE. #log4j.rootCategory=INFO, CONSOLE debug info warn error fatal log4j.rootCategory=debug, CONSOLE, LOGFILE # Set the enterprise logger category to FATAL and its only appender to CONSOLE. log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE # CONSOLE is set to be a ConsoleAppender using a PatternLayout. log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n # LOGFILE is set to be a File appender using a PatternLayout. log4j.appender.LOGFILE=org.apache.log4j.FileAppender log4j.appender.LOGFILE.File=d:\axis.log log4j.appender.LOGFILE.Append=true log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
7.在test.java下创建TestCRUD测试类
import com.cong.mapper.AccountMapper; import com.cong.pojo.Account; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.After; import org.junit.Before; import org.junit.Test; import java.io.InputStream; import java.util.List; public class TestCRUD { InputStream inputStream = null; SqlSession sqlSession = null; AccountMapper mapper = null; @Test public void findAll() { List<Account> accounts = mapper.findAll(); for (Account account : accounts) { System.out.println(account.toString()); } } @Test public void findById() { Account account = mapper.findById(2); System.out.println(account.toString()); } @Test public void findByName() { List<Account> accounts = mapper.findByName("%on%");//like #{name}写法 //List<Account> accounts = mapper.findByName("%on%");//like ‘%${value}%’ 写法 for (Account account : accounts) { System.out.println(account.toString()); } } @Test public void findTotal(){ int accountTotal = mapper.findTotal(); System.out.println("account total:" + accountTotal); } @Test public void save() { Account account = new Account(); account.setName("cong"); account.setMoney(1000f); mapper.saveAccount(account); //在mapper中写了返回自增对象的id,所以这里的对象会包含id属性 System.out.println(account.toString()); } @Test public void update() { Account account = new Account(); account.setName("cong"); account.setMoney(222); account.setId(2); mapper.updateAccount(account); } @Test public void deleteAccount() { mapper.deleteAccount(6); } @Before//在测试方法执行之前执行 public void init() throws Exception { //1.读取配置文件,生成字节输入流 inputStream = Resources.getResourceAsStream("SqlMapConfig.xml"); //2.获取SqlSessionFactoryBuilder SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream); //3.生成sqlSession sqlSession = factory.openSession(); //4.获取mapper的代理对象 mapper = sqlSession.getMapper(AccountMapper.class); } @After//在测试方法执行之后执行 public void close() throws Exception { //提交事务,增删改需要提交事务,数据库才会发生改变 sqlSession.commit(); //释放资源 sqlSession.close(); inputStream.close(); } }
8.完整目录
9.关于查询中的两种方式
一种是like #{name}
我们在配置文件中没有加入%来作为模糊查询的条件,所以在传入字符串实参时,就需要给定模糊查询的标
识%。 配置文件中的#{username}也只是一个占位符,所以 SQL 语句显示为“?”
查询语句 <select id="findByName" parameterType="String" resultType="account"> select * from account where name like #{name}; </select> 对应的test测试方法 List<Account> accounts = mapper.findByName("%on%")
在控制台,它的查询语句是
两外一种是like '%${value}%'
我们在上面将原来的#{}占位符,改成了${value}。注意如果用模糊查询的这种写法,那么${value}的写
法就是固定的,不能写成其它名字。
可以发现,我们在程序代码中就不需要加入模糊查询的匹配符%了,这两种方式的实现效果是一样的,但执行
的语句是不一样的
查询语句 <select id="findByName" parameterType="String" resultType="account"> select * from account where name like '%${value}%'; </select> 对应的test测试语句 List<Account> accounts = mapper.findByName("on");
在控制台,它的查询语句是
#{}与${}的区别
#{}表示一个占位符号
通过#{}可以实现 preparedStatement 向占位符中设置值,自动进行 java 类型和 jdbc 类型转换,
#{}可以有效防止 sql 注入。 #{}可以接收简单类型值或 pojo 属性值。 如果 parameterType 传输单个简单类
型值, #{}括号中可以是 value 或其它名称。
${}表示拼接 sql 串
通过${}可以将 parameterType 传入的内容拼接在 sql 中且不进行 jdbc 类型转换, ${}可以接收简
单类型值或 pojo 属性值,如果 parameterType 传输单个简单类型值, ${}括号中只能是 value。
查看以下模糊查询${value}的源码
这就说明了源码中指定了读取的 key 的名字就是”value”,所以我们在绑定参数时就只能叫 value 的名字
了
mybatis的代理mapper接口方式的执行过程,与此案例的不同
参考:https://www.cnblogs.com/lwjnicole/p/8358713.html