MyBatis
- MyBatis 不同与 Hiberanat
- MyBatis 比较轻 而 Hiberanat 比较重
这里的 轻 代表的是 方便学习,开发,维护,简单
初识MyBatis
MyBatis介绍
历史
iBATIS = “internet” + “abatis” 的组合
是Apache公司的一个开源项目,这个项目是做软件加密的
abatis 翻译过来是 路障,铁丝网的意思
后来转型成为一个基于Java的持久层框架
- 持久层
- Java中对象有两种状态
- 瞬态
- 持久态
- 瞬态
- new 了一个对象 用完之后垃圾回收
- 对象中的属性状态没有保存
- 持久态
- 对象的状态属性保持住了
- 保存的方法又很多种 :文件,数据库等
- 如果保存在数据库中,我们可以用JDBC来访问,操作
- 但是JDBC不是很方便,这样就产生了一种框架,叫做持久层框架
- Java中对象有两种状态
iBatis 后来改名为 MyBatis
因为跳槽,从Apache 跳槽到 Google 再到 Github
特点
- 开源的优秀持久层框架
- 轻
- SQL语句和代码分离
- 面向配置的编程(面向切片的编程)
- 增强程序的可维护性,可扩展性
- 良好支持复杂数据映射
- 使用JDBC我们会拼装SQL语句,这种语句并不安全,容易造成SQL注入
- MyBatis 使用 动态SQL 技术,替换拼装SQL语句
MyBatis环境搭建
下载
- 解压压缩文件
- 其中mybatis-..*.jar 是 MyBatis 的主jar包
- lib/ 文件夹是他的部分依赖包,毕竟曾经是Apache的项目
- mybatis-..*.pdf 是 说明文档
导入工程
- 导入 mybatis-..*.jar 包
- 导入 lib 中相关的 jar
- 导入 mysql 数据库 针对于 JDBC 的jar包
日志配置
-
为什么配置日志
-当我调试或者观察程序的时候,是通过输出的SQL语句看一下程序的执行状况- MyBatis 是通过 日志来完成的,所以要配置日志
-
加入日志配置文件log4.properties
-
改写日志输出级别为debug级别
- MyBatis 在日志输出的时候,SQL语句一定实在debug级别才能输出
- 如果是inform级,则不输出
log4j.rootLogger=DEBUG, Console
#Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
log4j.logger.java.sql.ResultSet=INFO
log4j.logger.org.apache=INFO
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
MyBatis工作流程
工作流程的步骤
- 读取配置文件
- 读取的是基本配置文件
- 包含的是连数据库的相关信息
- 生成SqlSessionFactory
- Sqlsession的工厂,用于建立与数据库之间的会话
- 建立SqlSession
- 用于执行Sql语句
- SqlSession 调用MyBatis提供的API
- 查询MAP配置
- Map配置文件里面存放的是sql语句
- 返回结果
- 不同的sql语句返回不同的结果
- 关闭SqlSession
工作流程的配置文件
- 基本配置文件
<?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="development"> # 一个environments 中有多个 environment
<environment id="development"> # 一个environment 代表连接的一个数据库 里面的是数据库的信息
<transactionManager type="JDBC"> #事务由谁来管理 这里是JDBC管理
</transactionManager>
<dataSource type="POOLED"> #是否用连接池 或者 第三方child
<property name="driver" value="com.mysql.jdbc.Driver"/> #驱动
<property name="url" value="jdbc:mysql://localhost:3306/jikebook"/> #链接路径
<property name="username" value="root"/> # 用户名
<property name="password" value="123"/> # 密码
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="jike/book/map/jikeUser.xml"/> #
</mappers>
</configuration>
包含着连数据库的基本信息
-
链接数据库的信息
- <environments>
- 就是环境,封装的就是连数据库的信息
-
map配置文件的数据位置
- <mappers>
- 映射map配置文件的路径信息
-
map配置文件
<?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="/">
<select id="findById" parameterType="int" resultType="jike.book.pojo.JiKeUser">
select * from jikeUser where id=#{id}
</select>
</mapper>
SqlSessionFactory, SqlSession
-
SqlSessionFactory代表着跟数据库之间的连接
-
连上去之后自然要进行各种各样的操作
-
各种各样的操作是由SqlSession去执行的
-
SqlSession是由SQLSessionFactory来建立的
-
生命周期
- SqlSessionFactory的生命周期是程序级的
- 一般一个MyBatis程序只有一个SqlSessionFactory
- 程序开始的时候建立,结束的时候才会消亡
- SqlSession 是过程级的
- 比如在一个方法当中会建立一个SqlSession,执行完后SqlSession就应该关闭了
- SqlSessionFactory的生命周期是程序级的
-
建立的代码
SqlSessionFactory sqlMapper = new SqlSessionFactoryBuilder().build(reader);
# reader 是一个输入流,是基本配置文件的路径的流
SqlSession session = sqlMapper.openSession();
Map文件
基本配置文件引用map文件
- 相对路径引用
<mappers>
<mapper resource="test/book/map/TestUser.xml"/>
</mappers>
- 绝对路径引用
<mappers>
<mapper url="file:///var/sqlmaps/AuthorMapper.xml" />
</mappers>
- 包路径引用
<package name="com.Test.mybatis.mapperinterface" />
什么是map文件
<select id="findById" parameterType="int" resultType="Test.book.pojo.TestUser">
select * from TestUser where id=#{id}
</select>
- 上述标签中的id,这是找到这个sql语句的标示
- 上述标签中的parameterType是参数类型
- 上述标签中的resultType指的是返回类型
- 上述的sql语句中id = #{id},’#'后面的内容代表一个参数
看实战,学操作,我有知识我自豪
建立数据库
create database jikebook;
use jikebook;
create table jikeUser(
id int not null auto_increment,
userName varchar(20) ,
password varchar(20) ,
primary key(id)
)engine=InnoDB default charset=utf8;
insert into jikeUser(id, userName, password)
values
(1, 'hello world', '');
查询代码
TestUser temp = session.selectOne("findById", 1); # 第一个参数是map配置中的id,第二个参数是 mysql数据库中 的id
System.out.println("name = " + temp.getUseName());
- jikeUser.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="test.book.map">
<select id="findById" parameterType="int" resultType="test.book.pojo.TestUser">
select * from jikeUser where id=#{id}
</select>
</mapper>
- MyBatisConfig.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="development">
<environment id="development">
<transactionManager type="JDBC">
</transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/jikebook"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="test/book/map/jikeUser.xml" />
</mappers>
</configuration>
- TestUser.java
package test.book.pojo;
public class TestUser {
private int id;
private String userName;
private String password;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
- MainTest.java
package test.book.pojo;
import java.io.IOException;
import java.io.Reader;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
String reource = "test/book/map/MyBatisConfig.xml";
Reader reader = null;
SqlSession session;
try {
reader = Resources.getResourceAsReader(reource);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
session.rollback();//回滚
}
System.out.println("111");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
System.out.println("222");
session =sqlSessionFactory.openSession();
TestUser temp = session.selectOne("findById", 1);
System.out.println(temp.getUserName());
}
}
MyBatis 基础操作
增删改
- 影响行数
insert
<insert id="insertUser" parameterType="TestUser" statementType="PREPARED" keyProperty="id" useGeneratedKeys="true">
insert into JikeUser (userName, password) values (#{userName, jdbcType=VARCHAR}, #{password, jdbcType=VARCHAR})
</insert>
- 上述代码中
- StatementType=“PERPARED” 代表这是一个 预处理的SQL语句
- parameterType=“TestUser” 代表传入的类
- 这里传入的应该是一个全路径名称,即com.jike.book.JikeUser
- 这里使用了typeAliases 标记 来定义了别名 简化了代码的书写
- keyProperty 代表 哪一个 参数 是主键
上一个大类中完成的基本配置中加上
<typeAliases>
<typeAlias alias="TestUser" type="test.book.pojo.TestUser" />
</typeAliases>
着重强调!!!
!!!!!!!!!!!
- Alias要写在environments前面,先定义别名,再配置环境,否则会报错
- 切记 切记
下面介绍代码
-
TestUser类依旧不变
-
MainTest类修改
package test.book.pojo;
import java.io.IOException;
import java.io.Reader;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
String reource = "test/book/map/MyBatisConfig.xml";
Reader reader = null;
SqlSession session;
try {
reader = Resources.getResourceAsReader(reource);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
session =sqlSessionFactory.openSession();
try {
TestUser testUser = new TestUser();
testUser.setUserName("laoziniubi");
testUser.setPassword("123456");
session.insert("insertUser", testUser);
session.commit();//提交sql语句
} catch (Exception e) {
e.printStackTrace();
session.rollback();//回滚
}finally {
session.close();
}
}
}
- jikeUser.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="test.book.map">
<select id="findById" parameterType="int" resultType="test.book.pojo.TestUser">
select * from jikeUser where id=#{id}
</select>
<insert id="insertUser" parameterType="TestUser" statementType="PREPARED" keyProperty="id" useGeneratedKeys="true">
insert into jikeUser (userName, password) values (#{userName}, #{password})
</insert>
</mapper>
- MyBatisConfig.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 alias="TestUser" type="test.book.pojo.TestUser" />
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">
</transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/jikebook"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="test/book/map/jikeUser.xml" />
</mappers>
</configuration>
Update
<update id="updateUser" parameterType="TestUser">
update jikeUser set userName=#{userName, jdbcType=VARCHAR},password=#{password,jdbcType=VARCHAR} where id=#{id,jdbcType=INTEGER}
</update>
- 上述代码中
- parameterType 仍然利用别名
- jdbcType 是 MyBatis 中 自动类型转换的一种设定
- java当中的数据类型 和 数据库当中的数据类型需要一个转换
- 这种转换 往往是自动完成的,但当不能自动转换的时候,就需要进行手动转换
下面介绍代码
- 就不介绍xml了,和之前一样,就加上 update 标签就行了
- 写一下调试代码
try {
TestUser testUser = new TestUser();
testUser.setUserName("laoziniubi");
testUser.setPassword("666666");
testUser.setId(2);
session.update("updateUser", testUser);
session.commit();//提交sql语句
} catch (Exception e) {
e.printStackTrace();
session.rollback();//回滚
}finally {
session.close();
}
delete(使用注解方式)
- 在map.xml的包中新建一个interface接口,名为JikeUserMapInterface
package test.book.map;
import org.apache.ibatis.annotations.Delete;
public interface JikeUserMapInterface {
@Delete("delete from jikeUser where id=#{id}")
public void deleteUder(int id);
}
- 在基本配置文件的mapper 标签中添加
<mappers>
<mapper resource="test/book/map/jikeUser.xml" />
<mapper class="test.book.map.JikeUserMapInterface" />
</mappers>
- 在TestMain调试文件中
try {
JikeUserMapInterface jkumi = session.getMapper(JikeUserMapInterface.class);
jkumi.deleteUder(1);//删除id为1的记录
session.commit();//提交sql语句
} catch (Exception e) {
e.printStackTrace();
session.rollback();//回滚
}finally {
session.close();
}
查询
- 返回集合
Select 参数 如何操作 如何得到结果集
<select id="selectPerson" parameterType="int" parameterMap="hashmap" resultType="hashmap" resultMap="personResultMap" flushCache="false" userCache="true" timeout="10000" fetchSize="256">
属性 | 描述 |
---|---|
id | 在命名空间中唯一的标识符,可以被用来引用这条语句 |
parameterType | 将会传入这条语句的参数类的完全限定名或类名 |
parameterMap | 这是引用外部parameterMap的已经被废弃的方法。使用内敛参数映射和parameterType属性 |
resultType | 从这条语句中返回的期望类型的类和完全限定名或别名。注意集合情形,那应该是集合可以包含的类型,而不能是集合。使用resultType或resultMa,但不能同时使用 |
resultMap | 命名引用外部的resultMap。返回map是MyBatis最具力量的特性,对其有一个很好的理解的话,许多复杂映射的清醒就能被解决了。 |
flushCache | 将其设为true,不能语句什么时候被调用,都会导致缓存被清空。默认值为false |
userCache | 将其设置为true,将会导致本条语句的结果被缓存。默认值为false |
timeout | 设置驱动程序等待数据库返回请求结果,并抛出异常时间的最大值。默认值不设定,驱动自行处理 |
fetchSize | 这是暗示驱动程序每次批量返回的结果函数。默认值不设置,程序自行控制 |
statementType | STATEMENT,PREPARED或CALLABLE的一种。这会让MyBatis选择使用Statement,PreparedStatement或Callable 的一种 |
resultSetType | FORWARD_ONLY,SCROLL_SENSITIVE,SCROLL_INSTENSITIVE中的一种。默认是不设置,驱动自行处理 |
- parameterType封装:hashmap
<select id="loginSelect" resultType="TestUser" parameterType="hashmap">
select * from jikeUser where userName=#{userName} and password=#{password}
</select>
老样子 把上述代码放在map.xml文件中
- 测试
HashMap(String, String) hm = new HashMap();
hm.put("userName", "laoziniubi");
hm.put("password", "666666");
-
上述的 “userName” 和 “password” 不仅是map的键,同时是 上述 select 标签中传入的参数名称
-
调用session 方法传入 hashmap
- TestUser ontemp = session.selectOne(“loginSelect”, hm);
-
调试代码
(使用hashmap)
try {
HashMap<String, String> hm = new HashMap<String, String>();
hm.put("userName", "laoziniubi");
hm.put("password","666666");
TestUser testUser = session.selectOne("loginSelect",hm);
if (testUser != null) {
System.out.println(testUser.getUserName() + " 欢迎回来");
}
} catch (Exception e) {
e.printStackTrace();
session.rollback();//回滚
}finally {
session.close();
}
-
调试代码
(使用对象)
- 对象参数自动匹配属性
- 如果对象属性与列名不一样用别名
-
这里 要修改xml文件的select标签
<select id="login2" resultType="TestUser" parameterType="TestUser" >
select * from jikeUser where userName=#{userName} and password=#{password}
</select>
- 然后是TestMain
try {
TestUser testUser = new TestUser();
testUser.setUserName("laoziniubi");
testUser.setPassword("666666");
TestUser getone = session.selectOne("login2", testUser);
if (getone != null) {
System.out.println(getone.getUserName() + " 欢迎回来");
}
} catch (Exception e) {
e.printStackTrace();
session.rollback();//回滚
}finally {
session.close();
}
返回多个查询
- 上述只是返回一个对象的情况,如果是返回多个对象呢?
- MyBatis会返回一个list
<select id="selectTestUserList" resultType="TestUser">
select * from jikeUser
</select>
- 测试函数中调用List 来接受list
try {
List<TestUser> ap = session.selectList("selectTestUserList");
for (TestUser testUser : ap) {
System.out.println(testUser.getUserName() + " 欢迎回来");
}
} catch (Exception e) {
e.printStackTrace();
session.rollback();//回滚
}finally {
session.close();
}
resultType 与 resultMap
-
resultType 与 resultMap 一样用于返回结果操作
- 但是,resultType 与 resultMap 只能用其中一个
-
区别是 resultMap 中可以解决一些比较复杂的映射问题
- 例如:一个对象含有另一个对象的引用
<resultMap id = "TestUserMap" type= "TestUser">
<id property="id" column="id" />
<result property="userName" column="userName" />
<result property="password" column="password" />
</resultMap>
-
上述中,如果类中的参数名与数据库中的参数名不一致的时候,可以使用resultMap来改变映射关系
-
使用resultMap
<select id="selectUsers" resultMap="TestUserMap">
select id,userName,password from jikeUser
</select>
-
上述代码中,resultMap 指明了使用 哪个resultMap
-
会按照resultMap的设定来返回对应的值
-
TestMain中的测试代码
try {
List<TestUser> ap = session.selectList("selectUsers");
for (TestUser testUser : ap) {
System.out.println(testUser.getUserName() + " 欢迎回来");
}
} catch (Exception e) {
e.printStackTrace();
session.rollback();//回滚
}finally {
session.close();
}
事物处理
事务处理配置
-
MyBatis的事务处理又两个选项
- JDBC
- JDBC代表的事
- 务处理由JDBC完成
- MANAGED
- MANAGED代表的事务处理由第三方的一些插件完成,例如Spring
- JDBC
-
事务处理的配置写在
基本配置文件当中
在基本配置文件当中(就是那个调用map.xml的xml文件啦)
有个 transactionManager 标签,tpye属性当中就是上述的JDBC或者MANAGED
事务处理方法
- MyBatis JDBC事务管理(典型代码)
- 关闭自动提交
try{
session = sqlMapper.openSession(false); // 关闭自动提交
操作 balabalbala.....
session.commit();// 提交事务
}
catch(Exception e){
session.rollback();//回滚
}
finally{
session.close(); //关闭session
}
Mybatis的Dao编写
- Mapper代理的开发方式,程序员只需要编写mapper接口(相当于Dao接口)
- Mybatis会自动的为mapper接口生成动态代理实现类
- 需要遵循开发规范
开发规范
- mapper接口的全限定名要和mapper映射文件的namespace相同
- mapper接口的方法名要和mapper映射文件中的statement的id相同
- mapper接口的方法参数只能有一个,且类型要和mapper映射文件中的statement的parameterType的值保持一致
- mapper接口的返回值类型要和mapper映射文件中的statement的resultType值或resultMao中的type值保持一致
- 图中三个箭头所指的两端是必须相同的
- 方法名与id参数相同
- namespace 与 接口相对路径相同
- 传入参数类型与ParameterType相同
个人书写样例
- 自己的工程目录
create table user(
id int primary key auto_increment, # 主键,int型,自增长
name varchar(18), # 姓名
sex bool, # 性别,0为男,1为女
birthday date, # 生日
address varchar(30), # 地址
UserName varchar(20), # 用户名
Mail varchar(30), # 邮箱
Password varchar(20), # 密码
bride int, # 婚姻状况0 未婚 1 离婚 2 丧偶
height int, # 身高
education varchar(20), # 学历
income int, # 收入
introduction varchar(100) # 个人简介
)charset=utf8;
- 建立表
#
# Copyright 2009-2016 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
### Global logging configuration
log4j.rootLogger=ERROR, stdout
### Uncomment for MyBatis logging
log4j.logger.org.apache.ibatis=ERROR
log4j.logger.org.apache.ibatis.session.AutoMappingUnknownColumnBehavior=WARN
### Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
log4j.appender.lastEventSavedAppender=org.apache.ibatis.session.lastEventSavedAppenderAutoMappingUnknownColumnBehaviorTest$LastEventSavedAppender
- log4j.properties日志配置文件
<?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的jar包添加到路径中 -->
<configuration>
<environments default="development"> <!-- 环境配置,可以配置多个环境,也就可以配置多个数据源(数据库) -->
<environment id="development">
<transactionManager type="JDBC"/><!-- 配置JDBC事物控制,由mybatis进行管理 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://你的ip地址/web2018?useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="用户名"/>
<property name="password" value="密码"/>
</dataSource>
</environment>
</environments>
<!-- 告诉mybatis加载映射文件的地址 -->
<mappers>
<mapper resource="com/module/SqlMap/User.xml"/>
<mapper resource="com/module/com/mapper/UserMapper.xml"></mapper>
</mappers>
</configuration>
- 自己的SqlMapConfig.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.SqlConn.User">
<!--
通过Id进行查询
parameterType 传入参数类型
resultType 返回类型
#{} 表示一个占位符
#{id} 表示该占位符待接受参数的名称为id,注意:如果参数为简单类型时,#{}里面的参数名称可以是任意定义
${} 用于拼接sql字符串,拼接可能导致sql注入,谨慎使用
${value} 表示要拼接的是简单类型参数。如果参数为简单类型,则必须使用value。int,byte,...String
-->
<select id="findUserById" parameterType="int" resultType="com.module.SqlConn.User">
select * from web2018.user where id = #{id}
</select>
<select id="findUserByMail" parameterType="String" resultType="com.module.SqlConn.User">
select * from web2018.user where mail = #{mail} <!-- 模糊查询 -->
</select>
<select id="findUserByName" parameterType="String" resultType="com.module.SqlConn.User">
select * from web2018.user where name LIKE '%${value}%' <!-- 模糊查询 -->
</select>
<!-- 简单类型必须是填写value -->
<!-- 如果是复杂对象,则括号中填写的是对应的属性名,调用其属性对应的get方法 -->
<insert id="insertUser" parameterType="com.module.SqlConn.User" >
insert into web2018.user (name, sex, birthday, address, userName, mail, password, bride, height, education, income)
value (#{name}, #{sex}, #{birthday}, #{address}, #{userName}, #{mail}, #{password}, #{bride}, #{height}, #{education}, #{income})
</insert>
<!-- 这里的占位 是写模型的属性 -->
<delete id="deleteUser" parameterType="String" >
delete from web2018.user where name=#{name}
</delete>
<update id="updateUser" parameterType="com.module.SqlConn.User" >
update web2018.user set address=#{address}, UserName=#{userName}
where name=#{name}
</update>
<insert id="insertUserReturnKey" parameterType="com.module.SqlConn.User" >
<!-- 通过selectKey查询主键 -->
<selectKey keyProperty="id" resultType="int" order="AFTER">
<!-- 关键字是Id,因为ID是int型,所以返回int,因为只有插入之后才知道自增值的id是多少,所以选择after -->
SELECT LAST_INSERT_ID()
<!-- 获取最后一次插入的主键 -->
</selectKey>
insert into web2018.user (name, sex, birthday, address, userName, mail, password, bride, height, education, income)
value (#{name}, #{sex}, #{birthday}, #{address}, #{userName}, #{mail}, #{password}, #{bride}, #{height}, #{education}, #{income})
</insert>
</mapper>
<!-- 作为User类的数据库映射文件 -->
- com/module/SqlMap/User.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">
<!-- 如果这里报错,就将mybatis的jar包添加到路径中 -->
<mapper namespace="com.module.com.mapper.UserMapper">
<select id="findUserByMaiil" parameterType="String" resultType="com.module.SqlConn.User">
SELECT * from web2018.user where mail=#{mail}
</select>
<insert id="save" parameterType="com.module.SqlConn.User">
insert into web2018.user (name, sex, birthday, address, userName, mail, password, bride, height, education, income)
value (#{name}, #{sex}, #{birthday}, #{address}, #{userName}, #{mail}, #{password}, #{bride}, #{height}, #{education}, #{income})
</insert>
</mapper>
<!-- xml文件名和前面的接口名一样 -->
<!-- 写完后记得在SqlMapConfig.xml中添加这个文件 -->
- com/module/com/mapper/UserMapper.xml文件
package com.module.SqlConn;
import javax.xml.crypto.Data;
import java.io.Serializable;
import java.util.Date;
public class User implements Serializable { // Serializables 将类的实例持久化保存
private int id;
private String Name; // 姓名
private boolean sex; // 性别 0为男,1为女
private Date Birthday; // 生日
private String address; // 地址
private String UserName; //用户名
private String Mail; //邮箱
private String Password; // 密码
private int Bride; // 婚姻 0 未婚 1 离婚 2 丧偶
private int Height; // 身高
private String Education; //学历
private int Income; // 收入
public User() {
}
public User(String name, boolean sex, Date birthday, String address, String userName, String mail, String password, int bride, int height, String education, int income) {
Name = name;
this.sex = sex;
Birthday = birthday;
this.address = address;
UserName = userName;
Mail = mail;
Password = password;
Bride = bride;
Height = height;
Education = education;
Income = income;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
public boolean isSex() {
return sex;
}
public void setSex(boolean sex) {
this.sex = sex;
}
public Date getBirthday() {
return Birthday;
}
public void setBirthday(Date birthday) {
Birthday = birthday;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getUserName() {
return UserName;
}
public void setUserName(String userName) {
UserName = userName;
}
public String getMail() {
return Mail;
}
public void setMail(String mail) {
Mail = mail;
}
public String getPassword() {
return Password;
}
public void setPassword(String passwd) {
Password = passwd;
}
public int getBride() {
return Bride;
}
public void setBride(int bride) {
Bride = bride;
}
public int getHeight() {
return Height;
}
public void setHeight(int height) {
Height = height;
}
public String getEducation() {
return Education;
}
public void setEducation(String education) {
Education = education;
}
public int getIncome() {
return Income;
}
public void setIncome(int income) {
Income = income;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", Name='" + Name + '\'' +
", sex=" + sex +
", Birthday=" + Birthday +
", address='" + address + '\'' +
", UserName='" + UserName + '\'' +
", Mail='" + Mail + '\'' +
", Passwd='" + Password + '\'' +
", Bride=" + Bride +
", Height=" + Height +
", Education='" + Education + '\'' +
", Income=" + Income +
'}';
}
}
- User类
package com.module.com.Dao.module;
import com.module.SqlConn.User;
public interface UserDao {
public void save(User user); // 保存用户
public User findUser(String mail); // 查找用户
}
- UserDao的接口类
package com.module.com.Dao.module;
import com.module.SqlConn.User;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
public class ImplUserDao implements UserDao {
private SqlSessionFactory ssf;
public ImplUserDao(SqlSessionFactory ssf) {
this.ssf = ssf;
}
public ImplUserDao() {
}
public void setSsf(SqlSessionFactory ssf) {
this.ssf = ssf;
}
@Override
public void save(User user) {
// 获取session
SqlSession session = ssf.openSession();
session.insert("insertUser", user);
session.commit();
session.close();
}
@Override
public User findUser(String mail) {
SqlSession session = ssf.openSession();
User user = session.selectOne("findUserByMail", mail);
session.commit();
session.close();
return user;
}
}
- implUserDao 是 接口实现类
package com.module.com.mapper;
import com.module.SqlConn.User;
public interface UserMapper {
public int save(User user); // 保存用户 返回受影响行数
public User findUserByMaiil(String mail); // 查找用户
}
- UserMapper 是 mybatis 的mapper来实现Dao的功能
package com.module.com.module.builder;
import com.module.SqlConn.User;
import com.module.com.Dao.module.ImplUserDao;
import com.module.com.Dao.module.UserDao;
import com.module.com.mapper.UserMapper;
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.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
public class test {
private SqlSession session;
private SqlSessionFactory sessionFactory;
@Before
public void before() throws IOException {
System.out.println("before");
// 读取配置文件
String source = "SqlMapConfig.xml";
InputStream is = Resources.getResourceAsStream(source); // 这里因为配置文件直接放在src目录下,所以前面没有其他路径。会抛出IO异常∂
// 通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂
sessionFactory = new SqlSessionFactoryBuilder().build(is);
// 通过SqlSessionFactory创建SqlSession
session = sessionFactory.openSession();
}
@After
public void after(){
// 关闭Session
session.commit();
System.out.println("after");
}
// 单一变量查询
@Test
public void test1() throws IOException {
// 调用SelSession的操作数据库方法
User user = session.selectOne("findUserById", 1); // 如果查询出来的值大于1条,则报错
System.out.println(user.toString());
}
// 模糊查询
@Test
public void test2() throws IOException{
// 读取配置文件
InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml"); // 这里因为配置文件直接放在src目录下,所以前面没有其他路径。会抛出IO异常∂
// 通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);
// 通过SqlSessionFactory创建SqlSession
SqlSession session = sessionFactory.openSession();
// 调用SelSession的操作数据库方法
List<User> user = session.selectList("findUserByName", "中");
System.out.println(user);
// 关闭Session
session.commit();
}
//插入
@Test
public void test3() {
Date time = new Date(System.currentTimeMillis());
User user = new User("英文", true, time, "com.module.builder", "学习英文", "459674158@qq.com", "123456", 0, 160, "高中", 7000);
int rows = session.insert("insertUser", user);
System.out.println("受影响的行数" + rows);
}
//删除
@Test
public void test4(){
int rows = session.delete("deleteUser","中文");
System.out.println("受影响行数" + rows);
}
//更新
@Test
public void test5(){
Date time = new Date(System.currentTimeMillis());
User user = new User("中文", true, time, "com.module.Chinese", "我爱学习中文", "71461786152@qq.com", "123456", 0, 160, "高中", 7000);
int rows = session.update("updateUser", user);
System.out.println("受影响行数" + rows);
}
// 插入后,往模型中设置ID,因为我的id是自增的,所以不能提前设置
@Test
public void test6(){
Date time = new Date(System.currentTimeMillis());
User user = new User("法语", true, time, "com.module.builder", "学习法语", "45454321358@qq.com", "123456", 0, 160, "高中", 7000);
int rows = session.insert("insertUserReturnKey", user);
System.out.println("受影响的行数" + rows + " ID = " + user.getId());
}
// 传统数据库 的 Dao编写
@Test
public void test7() throws IOException {
// 调用Dao
UserDao userDao = new ImplUserDao(sessionFactory);
User user = userDao.findUser("164841508@qq.com");
System.out.println(user.toString());
}
// Mybatis 的 Dao编写【mapper代理方式实现】
@Test
public void test8(){
UserMapper userMapper = session.getMapper(UserMapper.class);//直接获取我们写的接口
//返回的是一个代理类
System.out.println(userMapper.findUserByMaiil("164841508@qq.com"));
}
}
- Test所有功能的测试类
全局配置文件
- 上述 SqlMapConfig.xml里面存储了很多的数据库信息,但是如果我们需要修改部分信息,难道要一个文件一个文件的修改吗?
- 通过db.properties文件可以作为配置文件让SqlMapConfig.xml自动装配
driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql://ip地址/web2018?useUnicode=true&characterEncoding=utf8
username=用户名
password=密码
- 然后在SqlMapConfig.xml中对应参数就行了
<configuration>
<properties resource="db.properties"></properties>
<!--resource中填写上述配置文件db.properties文件的相对地址-->
<environments default="development"> <!-- 环境配置,可以配置多个环境,也就可以配置多个数据源(数据库) -->
<environment id="development">
<transactionManager type="JDBC"/><!-- 配置JDBC事物控制,由mybatis进行管理 -->
<dataSource type="POOLED">
<property name="driver" value="${driverClass}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!-- 告诉mybatis加载映射文件的地址 -->
<mappers>
<mapper resource="com/module/SqlMap/User.xml"/>
</mappers>
</configuration>
配置别名
- 可以不用像之前一样填写很长的包名+类名
- 可以用别名来代替包名+类名
<typeAliases>
<typeAlias type="com.module.test" alias="test">
<typeAlias alias="TestUser" type="test.book.pojo.TestUser" />
</typeAliases>
- 其实配置别名并不是最好的解决方式,如果我们的dao特别多,配置别名也是个容易出错的和繁琐的事情
<typeAliases>
<!-- 指定包名,别名就是类名,第一个字母小写 User->user -->
<package name="com.module.SqlConn"></package>
</typeAliases>
注解写法
- 其实并不推荐注解,多表查询,多值查询不灵活
package com.module.com.Dao.module;
import com.module.SqlConn.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
public interface UserDao {
@Insert("insert into web2018.user (name, sex, birthday, address, userName, mail, password, bride, height, education, income) value (#{name}, #{sex}, #{birthday}, #{address}, #{userName}, #{mail}, #{password}, #{bride}, #{height}, #{education}, #{income})")
public void save(User user); // 保存用户
@Select("select * from web2018.user where mail = #{mail}")
public User findUser(String mail); // 查找用户
}
Mybatis映射文件
ParameterType
-
指定输入参数的java类型,可以使用别名或者类的全限定名。
-
可以接受简单类型,POJO对象,HashMap
-
传递POJO包装类对象
public class UserQueryVO{
private User user;
public User getUser(){
return user;
}
public void setUser(User user){
}
}
逆向工程
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<classPathEntry location="/Program Files/IBM/SQLLIB/java/db2java.zip" />
<context id="DB2Tables" targetRuntime="MyBatis3">
<!--数据库连接-->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhose:3306/mydb"
userId="root"
password="123456">
</jdbcConnection>
<!---->
<javaTypeResolver >
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!--生成pojo类的位置-->
<javaModelGenerator targetPackage="com.mybatis.mapper" targetProject=".\src">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!--生成Mapper映射文件的位置-->
<sqlMapGenerator targetPackage="test.xml" targetProject="\MBGTestProject\src">
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<!--生成mapper接口的位置 targetProject 就是你工程下的src里面所以一般写.\src就行-->
<javaClientGenerator type="XMLMAPPER" targetPackage="test.dao" targetProject=".\src">
<property name="enableSubPackages" value="true" />
</javaClientGenerator>
<!--指定数据库表-->
<table schema="DB2ADMIN" tableName="ALLTYPES" domainObjectName="Customer" >
<property name="useActualColumnNames" value="true"/>
<generatedKey column="ID" sqlStatement="DB2" identity="true" />
<columnOverride column="DATE_FIELD" property="startDate" />
<ignoreColumn column="FRED" />
<columnOverride column="LONG_VARCHAR_FIELD" jdbcType="VARCHAR" />
</table>
</context>
</generatorConfiguration>
- 修改上述xml对应位置
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
File configFile = new File("generatorConfig.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
myBatisGenerator.generate(null);
- 运行上述java代码
问题
-
log4j:WARN No appenders could be found for logger 的解决办法
- 可能是你的log4j.properties 文件需要放到src下,而不能是其他位置
-
明明MyBatis逆向运行成功了,但是就是没有生成文件
- 可能是你的路径有问题!!!
- 上述的
.\src
是 Windows 的写法,而linux和mac的写法应该是./src
大坑
-
自动生成的example有啥用
- 用于查询
UsrsExample example = new UsrsExample();
UsrsExample.Criteria criteria = example.createCriteria();
criteria.andUsrbirthBetween(new Date(), new Date());
List<Usrs> usrs = userMapper.selectByExample(example);
- 你看看上面的criteria中的各种方法,都可以方便你查找
- Between 就是查找值在两个参数之间的
- EqualTo 就是查找值相同的
- GratherThan 就是查找大于的
- LessThan 查找小于的
- 等等
- 之后再将example传入查找,就很方便