HelloWorld
依赖
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId> <!-- 仅仅为测试而加 -->
<version>4.12</version>
</dependency>
</dependencies>
表设计
create table `user` (
`id` int ,
`name` varchar ,
`age` int
);
insert into `user` (`id`, `name`, `age`) values('1','林更新','18');
resource下mybatis-config.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 配置多个environment,供切换 -->
<environments default="development"> <!--default指定一个默认环境的id-->
<environment id="development">
<!-- type:处理事务方式, 大多数情况使用jdbc,另一种 managed:将事物交给其他组件托管,如spring-->
<transactionManager type="JDBC" />
<!-- 配置数据库连接类型
POOLED:常用的简单的JDBC配置,使用了连接池
UNPOOLED:不使用连接池,每次均需要打开和关闭数据连接,很消耗性能,相当于DriverManager.getConnection(url,username,password)
JDNI:从tomcat中获取一个内置的数据库连接池
-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/cpt" />
<property name="username" value="root" />
<property name="password" value="123456" />
</dataSource>
</environment>
</environments>
<mappers>
<!-- package 注册包下面的所有Mapper接口 -->
<!-- <package name="com.baidu.cpt.mapper"/>-->
<!-- resource属性 注册单个相对于类路径的Mapper.xml文件 -->
<mapper resource="com/baidu/cpt/mapper/UserMapper.xml"/>
<!-- url属性 注册一个绝对路径的的Mapper.xml文件 -->
<!-- <mapper url="file:///E:/UserMapper.xml"/> -->
<!-- class属性 注册一个Mapper接口,接口必须与mapper.xml文件名同名,且同路径下 -->
<!-- <mapper class="com.baidu.cpt.mapper.userMapper"/>-->
</mappers>
</configuration>
Entity包中User.java
public class User {
private int id;
private String name;
private int age;
//toString、全参构造、set、get、toString 此处全部省略。。。实际开发必须有,不然代码报错
}
Util包中:MybatisUtil.java
public class MyBatisUtil {
public static SqlSessionFactory getSqlSessionFactory() throws IOException {
String resource = "mybatis-config.xml";
InputStream is = Resources.getResourceAsStream(resource);//使用类加载器加载mybatis的配置文件
//构建sqlSession的工厂 build方法还可以追一个参数,指定环境environment标签的id
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
return sqlSessionFactory;
}
public static SqlSession getSqlSession() throws IOException{
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
return sqlSessionFactory.openSession();//若是设置为opsenSession(true)默认自动提交事务,就不需要手动commit
}
}
mapper包中UserMapper.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.baidu.cpt.mapper.UserMapper">
<!-- namespace为mapper指定唯一的id,通常设置成包名+sql映射的文件名-->
<!-- 这里namespace不建议写xml文件全名,这种方式已过时,建议写接口全名,使用面向接口的优秀方式 -->
<!-- parameterType指明查询时使用的参数类型。如果参数只有1个则用简单类型,参数为多个时可用Map集合或实体对象,占位符必须用对象的属性名;
resultType表示查询结果将要封装成的实体类,也可以为对象类型、Map类型、基本类型 -->
<select id="selectOneUser" resultType="com.baidu.cpt.Entity.User" parameterType="int">
select * from user where id = #{id}
</select>
<!-- useGeneratedKeys 设置保存时返回主键,true 开启,自动封装到对象中对应的属性,默认是false -->
<!-- keyProperty 指定对象的哪个属性的主键 -->
<insert id="insertUser" parameterType="com.baidu.cpt.Entity.User" useGeneratedKeys="true" keyProperty="id">
insert into user(name, age) values(#{name}, #{age})
</insert>
<delete id="deleteUser">
delete from user where id=#{id}
</delete>
<update id="updateUser" parameterType="com.baidu.cpt.Entity.User" >
update user set nam e= #{name},age = #{age} where id = #{id}
</update>
<select id="selectAllUser" resultType="com.baidu.cpt.Entity.User">
select * from user
</select>
</mapper>
test文件夹中Test.java
public class Test {
public static void main(String[] args) throws Exception{
SqlSession session = MyBatisUtil.getSqlSession();//至此得到一个session
//Unhandled Exception:java.io.IOException 是因为少了throws Exception或者try/catch
//org.apache.ibatis.binding.BindingException: Type interface xxx is not known to the MapperRegistry
//上面的错误时因为namespace和接口名不相同,必须改为相同
String namespace = "com.baidu.cpt.mapper.UserMapper.";//注意后面有一个点,为了和后面的mapper文件中的id连接
String statement4 = namespace+"selectOneUser";
User user = session.selectOne(statement4,1);
//selectOne sql中需要一个参数就传一个,这里查出来几个字段,都会按照实体类构造方法按顺序进行赋值
System.out.println("selectOne:"+user);
String statement1 = namespace+"insertUser";//映射sql的标识字符串
int insert = session.insert(statement1,new User(10,"张三",18));
//insert 这里为什么插入后id并不是指定的10,因为该namespace中sql语句中没有插入id字段,而建表时主键id是自动增长的。
session.commit(); //默认增删改 必须手动提交提交事务
System.out.println("insert:"+insert);
String statement2 = namespace+"deleteUser";
int delete = session.delete(statement2,2);
session.commit(); //默认增删改 必须手动提交提交事务
System.out.println("delete:"+delete);
String statement3 = namespace+"updateUser";
int update = session.update(statement3,new User(1,"林更新",18));
session.commit(); //默认增删改 必须手动提交提交事务
System.out.println("update:"+update);
String statement5 = namespace+"selectAllUser";
List<User> list = session.selectList(statement5);
System.out.println("selectList:"+list);
session.close();//必须释放session
}
}
三种方式区别
1,xml
<!-- mybatis-config.xml 中注册:UserMapper.xml,使用命名空间来找到 select 标签 -->
<mappers>
<package name="com.baidu.cpt.mapper"/>
</mappers>
2,xml + interface(推荐,且最流行)
// 1,xml不变
// 2,增加接口
public interface UserMapper {
public List<User> selectAllUser(); // 方法名必须和mapper文件的select标签id一致,mapper代理要求名字保持一致
}
// 3,测试方法和纯xml方式也不同,使用反射,根据接口类, 而不是namespace
UserMapper userMapper = session.getMapper(UserMapper.class);
List<User> lists = userMapper.selectAllUser();
for (User u : lists ) {
System.out.println(u);
}
// 4,不再是注册xml,而是注册接口
<mappers>
<package name="com.baidu.cpt.mapper"/>
</mappers>
3,interface + anotation
只需要interface,不再需要userMapper.xml,注解将sql写在方法上,当有注解时,默认使用方式三,但只适用简单sql
注意要同名,因为如下:
本质:反射机制实现
底层:动态代理!
// 1,新建一个接口文件,调用的方法不再是select标签,而是注解中sql
public interface UserMapperNew {
@Select ( "select * from user" )
public List<User> selectAllUserNew() throws Exception;
@Insert( "insert into user(name, age) values(#{name}, #{age})" )
public int insertUser(User user) throws Exception;
@Delete( "delete from user where id=#{id}" )
public int deleteUser(int id) throws Exception;
@Update( "update user set name=#{name},age=#{age} where id=#{id}" )
public int updateUser (User user,int id) throws Exception;
@Select( "select * from user where id = #{id}" )
public User selectOneUser(int id) throws Exception;
}
// 2,测试方法,调接口的方法,方法名无需和select标签一致,因为使用的该方法的注解中的sql,与userMapper.xml文件无关。
UserMapperNew userMapper = session.getMapper(UserMapperNew.class);
List<User> lists = userMapper.selectAllUserNew();
for (User u : lists ) {
System.out.println(u);
}
other
关于@Param()注解
- 基本类型的参数或者String类型,需要加上,相当于给形参指定一个传入sql的固定名字,必须和sql中名字对应
- 引用类型不需要加
- 如果只有一个基本类型的话,可以忽略,但是建议大家都加上
- 我们在SQL中引用的就是我们这里的@Param()中设定的属性名
useGeneratedKeys="true"
<insert id="insertUser" parameterType="com.huawei.cpt.vo.User" useGeneratedKeys="true" keyProperty="id">
insert into user (id,name,age) values(#{id},"Dandy","123456@a")
</insert>
User类的id为主键,这里useGeneratedKeys="true"表示需要使用自增这个功能,keyProperty="id"表示把自增值取到后存入参数对象的id属性中,用于sql中赋值,所以该实体类必须有该属性,且有setter方法;既然从表里取自增值,那么表必须设置为自增。
AUTO_INCREMENT
假设,id此时自增到了10,然后手动插入一条记录,id为15,继续使用程序插入数据,会使用当前自增值,此时是11还是15,答案是:15,自增值会自动取最大值。
selectKey
查出一个随机数,作为user实体类的id属性进行赋值,然后insert into中取到这个id值进行数据插入;
所以User类中必须有id属性,且有setter方法,resultType也必须和User的id类型对应;
selectKey也有注解,但注解适用简单sql,就不研究了。太low
<insert id="insertUser" parameterType="com.huawei.cpt.vo.User">
<selectKey keyProperty="id" order="BEFORE" resultType="int">
select CEILING(RAND()*10000)
</selectKey>
insert into user (id, name, age) values (#{id}, #{name}, #{age})
</insert>