-
Notifications
You must be signed in to change notification settings - Fork 26
Reload SQL dynamically
zzg edited this page Mar 21, 2017
·
1 revision
使用前,请参考 这里 先安装插件
1: 假定数据库为本机: test, 用户名和密码均为: root
@DB(url="jdbc:mysql://localhost:3306/test?allowMultiQueries=true"
,username="root",password="root")
public interface TestDB {
//该定义方便后续直接执行查询
public static DBConfig DB=DBConfig.fromClass(TestDB.class);
}
2: 创建测试表和数据
执行下面的代码 或 使用数据库工具运行其中的SQL
public class Create {
public static void main(String[] args) {
TestDB.DB.execute(""/**~{
DROP TABLE IF EXISTS `user` ;
DROP TABLE IF EXISTS `blog` ;
CREATE TABLE IF NOT EXISTS `user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
`name` varchar(64) NOT NULL COMMENT '用户名称',
`passwd` varchar(64) DEFAULT '123456' COMMENT '用户密码' ,
`status` int(11) DEFAULT 1 COMMENT '用户状态',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT '用户表';
CREATE TABLE IF NOT EXISTS `blog` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '博客ID',
`user_id` int(11) NOT NULL COMMENT '用户ID',
`title` varchar(64) NOT NULL COMMENT '博客标题',
`content` text DEFAULT NULL COMMENT '博客内容' ,
`create_time` DATETIME NOT NULL COMMENT '创建时间' ,
`status` int(11) DEFAULT NULL COMMENT '博客状态',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT '博客表';
INSERT INTO `user`(id,name,passwd,status)VALUES(1,"zzg1","123",1);
INSERT INTO `user`(id,name,passwd,status)VALUES(2,"zzg2","123",1);
INSERT INTO `user`(id,name,passwd,status)VALUES(3,"zzg3","123",1);
INSERT INTO `blog`(user_id,title,content,status,create_time)VALUES
(1,'Hello-11','Test Content 11',1,now()),
(1,'Hello-12','Test Content 12',1,now()),
(1,'Hello-13','Test Content 13',1,now()),
(1,'Hello-14','Test Content 14',0,now()),
(1,'Hello-15','Test Content 15',0,now());
}*/);
}
}
数据访问类,建议该类只涉及数据库相关的一些操作, 不要引入复杂的业务逻辑。
public class UserBlogDao {
final static long $VERSION$= 18L; //!!! 版本号, 每次保存为自动 +1
//@Select 注解指示该方法需自动生成结果类
//默认类名: Result + 方法名, 默认包名:数据访问类的包名+"."+数据访问类的名称(小写)
//可选参数:name 指定生成结果类的名称
@Select(name="test.result.UserBlogs")
//!!! 保存后会自动修改该函数的返回值为: List -> List<UserBlogs>
//第一次编写时,由于结果类还不存在, 为了保证能够编译正常,
//函数的返回值 和 查询结果要用 泛值 替代, 保存后,插件会自动修改.
//函数的返回值 和 查询结果 泛值的对应关系分三类如下:
//1. List查询
//public DataTable method_name(...){... return Query.getList(); } 或
//public List method_name(...){... return Query.getList(); }
//
//2. Page查询
//public Page method_name(...){... return Query.Page(); }
//
//3. 单条记录
//public Object method_name(...){... return Query.getResult(); }
//
public List<UserBlogs> selectUserBlogs(int user_id){
Query q=TestDB.DB.createQuery();
q.add(""/**~{
SELECT a.id,a.name,b.title, b.content,b.create_time
FROM user a, blog b
WHERE a.id=b.user_id AND a.id=?
}*/, user_id);
//!!! 保存后会自动修改 查询结果为: getList() -> getList<UserBlogs.class>
return q.getList(UserBlogs.class);
}
@Select //自动产生结果类: test.dao.userblogdao.ResultSelectUserBlogsOne
public ResultSelectUserBlogsOne selectUserBlogsOne(int user_id){
Query q=TestDB.DB.createQuery();
q.add(""/**~{
SELECT a.id,a.name,b.title, b.content,b.create_time
FROM user a, blog b
WHERE a.id=b.user_id AND a.id=?
}*/, user_id);
return q.getResult(ResultSelectUserBlogsOne.class);
}
@Tx //在一个事务中运行这个方法
public void updateUserBlog(int user_id,int blog_id){
User user=User.SELECT().selectByPrimaryKey(user_id);
Blog blog=Blog.SELECT().selectByPrimaryKey(blog_id);
user.setName("new name").update();
blog.setContent("new content").update();
}
//使用Map存储查询结果
public Page<DataMap> selectUserBlogsAsListMap(int user_id,int limit,int offset){
Query q=TestDB.DB.createQuery();
q.add(""/**~{
SELECT a.id,a.name,b.title,b.content,b.create_time
FROM user a, blog b
WHERE a.id=b.user_id AND a.id=?
}*/, user_id);
return q.getPage(limit,offset);
}
}
public class UserAction {
public static void main(String[] args)throws Exception {
UserAction action=new UserAction();
action.findUserBlogs(1);
}
/**
* 这里需要调用 Query.Create()来创建数据访问类.
* 不能直接调用new, 否则会丢失@Tx标记方法的事务特性, 以及数据访问类更新加载的特性
*/
private UserBlogDao dao=Query.create(UserBlogDao.class);
public void findUserBlogs(int user_id){
for(UserBlogs x: dao.selectUserBlogs(user_id)){
System.out.println(x.getContent());
}
}
}
将修改后的 UserBlogDao.java 文件(可包含子目录) 放置到目录 ./monalisa/agent即可实现在运行时更新数据访问接口.
受限于JVM的代码热修改, 动态更新的数据访问类有如下一些限制
- 不能增加或修改方法的签名
- 不能增加或修改类的成员变量 (但方法中的变量和代码可以任意修改)
数据访问类的更新判断标准为:
- 如果类包含有版本号字段:
$VERSION$ , 则加载最高的版本号作为运行的类 - 否则比较运行期的.class和agent/*.java文件的更新日期, 加载最新的日期作为运行的类
类更新时会输入如下日志信息:
Reload classes(1), Class-Path: ./target/monalisa/_java
*******************************************************************************
<Replace> class: test.dao.UserBlogDao, version: 1 -> 2, timestamp: xxx-> yyy
*******************************************************************************