Mybatis 基础

MyBatis

  • MyBatis 不同与 Hiberanat
  • MyBatis 比较轻 而 Hiberanat 比较重
    这里的 轻 代表的是 方便学习,开发,维护,简单

初识MyBatis

MyBatis介绍

历史

iBATIS = “internet” + “abatis” 的组合
是Apache公司的一个开源项目,这个项目是做软件加密的
abatis 翻译过来是 路障,铁丝网的意思
后来转型成为一个基于Java的持久层框架

  • 持久层
    • Java中对象有两种状态
      • 瞬态
      • 持久态
    • 瞬态
      • new 了一个对象 用完之后垃圾回收
      • 对象中的属性状态没有保存
    • 持久态
      • 对象的状态属性保持住了
      • 保存的方法又很多种 :文件,数据库等
    • 如果保存在数据库中,我们可以用JDBC来访问,操作
    • 但是JDBC不是很方便,这样就产生了一种框架,叫做持久层框架

iBatis 后来改名为 MyBatis
因为跳槽,从Apache 跳槽到 Google 再到 Github

特点
  • 开源的优秀持久层框架
  • SQL语句和代码分离
  • 面向配置的编程(面向切片的编程)
  • 增强程序的可维护性,可扩展性
  • 良好支持复杂数据映射
  • 使用JDBC我们会拼装SQL语句,这种语句并不安全,容易造成SQL注入
  • MyBatis 使用 动态SQL 技术,替换拼装SQL语句

MyBatis环境搭建

下载

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工作流程

工作流程的步骤
  1. 读取配置文件
    • 读取的是基本配置文件
    • 包含的是连数据库的相关信息
  2. 生成SqlSessionFactory
    • Sqlsession的工厂,用于建立与数据库之间的会话
  3. 建立SqlSession
    • 用于执行Sql语句
  4. SqlSession 调用MyBatis提供的API
  5. 查询MAP配置
    • Map配置文件里面存放的是sql语句
  6. 返回结果
    • 不同的sql语句返回不同的结果
  7. 关闭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 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这是暗示驱动程序每次批量返回的结果函数。默认值不设置,程序自行控制
statementTypeSTATEMENT,PREPARED或CALLABLE的一种。这会让MyBatis选择使用Statement,PreparedStatement或Callable 的一种
resultSetTypeFORWARD_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的事务处理又两个选项

    1. JDBC
      • JDBC代表的事
      • 务处理由JDBC完成
    2. MANAGED
      • MANAGED代表的事务处理由第三方的一些插件完成,例如Spring
  • 事务处理的配置写在基本配置文件当中

在基本配置文件当中(就是那个调用map.xml的xml文件啦)
有个 transactionManager 标签,tpye属性当中就是上述的JDBC或者MANAGED

事务处理方法
  • MyBatis JDBC事务管理(典型代码)
  1. 关闭自动提交
try{
	session = sqlMapper.openSession(false); // 关闭自动提交
	操作 balabalbala.....
	session.commit();// 提交事务	 
}
catch(Exception e){
	session.rollback();//回滚
}
finally{
	session.close(); //关闭session
}

Mybatis的Dao编写

  • Mapper代理的开发方式,程序员只需要编写mapper接口(相当于Dao接口)
  • Mybatis会自动的为mapper接口生成动态代理实现类
  • 需要遵循开发规范

开发规范

  1. mapper接口的全限定名要和mapper映射文件的namespace相同
  2. mapper接口的方法名要和mapper映射文件中的statement的id相同
  3. mapper接口的方法参数只能有一个,且类型要和mapper映射文件中的statement的parameterType的值保持一致
  4. 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&amp;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&amp;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传入查找,就很方便
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值